1.引言

Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性。而近年来,Linux操作系统在嵌入式系统领域的延伸也可谓是如日中天,许多版本的嵌入式Linux系统被开发出来,如ucLinux、RTLinux、ARM-Linux等等。在嵌入式操作系统方面,Linux的地位是不容怀疑的,它开源、它包含TCP/IP协议栈、它易集成GUI。
 鉴于Linux操作系统在服务器和嵌入式系统领域愈来愈广泛的应用,社会上越来越需要基于Linux操作系统进行编程的开发人员。
浏览许多论坛,经常碰到这样的提问:“现在是不是很流行unix/linux下的c编程?所以想学习一下!但是不知道该从何学起,如何下手!有什么好的建议吗?各位高手!哪些书籍比较合适初学者?在深入浅出的过程中应该看哪些不同层次的书?比如好的网站、论坛请大家赐教!不慎感激!”
鉴于读者的需求,在本文中,笔者将对Linux平台下C编程的几个方面进行实例讲解,并力求回答读者们关心的问题,以与读者朋友们进行交流,共同提高。
在本文的连载过程中,有任何问题或建议,您可以给笔者发送email:21cnbao@21cn.com,您也可以进入笔者的博客参与讨论: http://blog.donews.com/21cnbao。
笔者建议在PC内存足够大的情况下,不要直接安装Linux操作系统,最好把它安装在运行VMWare虚拟机软件的Windows平台上。
在Linux平台下,可用任意一个文本编辑工具编辑源代码,但笔者建议使用emacs软件,它具备语法高亮、版本控制等附带功能。

2.GCC编译器
 GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,其基本用法为:
gcc [options] [filenames]
options为编译选项,GCC总共提供的编译选项超过100个,但只有少数几个会被频繁使用,我们仅对几个常用选项进行介绍。
假设我们编译一输出“Hello World”的程序:
/* Filename:helloworld.c */
main()
{
    printf("Hello World\n");
}
最简单的编译方法是不指定任何编译选项:
gcc helloworld.c
它会为目标程序生成默认的文件名a.out,我们可用-o编译选项来为将产生的可执行文件指定一个文件名来代替a.out。例如,将上述名为helloworld.c的C程序编译为名叫helloworld的可执行文件,需要输入如下命令:
gcc –o helloworld helloworld.c
-c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤;
-S 编译选项告诉GCC 在为 C代码产生了汇编语言文件后停止编译。GCC 产生的汇编语言文件的缺省扩展名是.s,上述程序运行如下命令:
gcc –S helloworld.c 
将生成helloworld.c的汇编代码,使用的是AT&T汇编。用emacs打开汇编代码。
 
-E选项指示编译器仅对输入文件进行预处理。当这个选项被使用时,预处理器的输出被送到标准输出(默认为屏幕)而不是储存在文件里。
-O选项告诉GCC对源代码进行基本优化从而使得程序执行地更快;而-O2选项告诉GCC产生尽可能小和尽可能快的代码。使用-O2选项编译的速度比使用-O时慢,但产生的代码执行速度会更快。
-g选项告诉GCC产生能被GNU调试器使用的调试信息以便调试你的程序,可喜的是,在GCC里,我们能联用-g和-O (产生优化代码)。
-pg选项告诉GCC在你的程序里加入额外的代码,执行时,产生gprof用的剖析信息以显示你的程序的耗时情况。
3.GDB调试器
 GCC用于编译程序,而Linux的另一个GNU工具gdb则用于调试程序。gdb是一个用来调试C和C++程序的强力调试器,我们能通过它进行一系列调试工作,包括设置断点、观查变量、单步等。
其最常用的命令如下:
file:装入想要调试的可执行文件。 
kill:终止正在调试的程序。 
list:列表显示源代码。 
next:执行一行源代码但不进入函数内部。 
step:执行一行源代码而且进入函数内部。 
run:执行当前被调试的程序 
quit:终止gdb
watch:监视一个变量的值 
break:在代码里设置断点,程序执行到这里时挂起 
make:不退出gdb而重新产生可执行文件
shell:不离开gdb而执行shell
下面我们来演示怎样用GDB来调试一个求0+1+2+3+…+99的程序:
/* Filename:sum.c */
main()
{
  int i, sum;

sum = 0;
  for (i = 0; i < 100; i++)
  {
    sum +  = i;
  }

printf("the sum of 1+2+...+ is %d", sum);
}
执行如下命令编译sum.c(加-g选项产生debug信息):
gcc –g –o sum sum.c
在命令行上键入gdb sum并按回车键就可以开始调试sum了,再运行run命令执行sum。
 
list命令:
list命令用于列出源代码,对上述程序两次运行list,将出现如下画面(源代码被标行号)。
 
根据列出的源程序,如果我们将断点设置在第5行,只需在gdb 命令行提示符下键入如下命令设置断点:(gdb) break 5。

这个时候我们再run,程序会停止在第5行。

设置断点的另一种语法是 break <function>,它在进入指定函数(function)时停住。
相反的,clear用于清除所有的已定义的断点,clear <function>清除设置在函数上的断点,  clear <linenum>则清除设置在指定行上的断点。
watch命令:
watch命令用于观查变量或表达式的值,我们观查sum变量只需要运行watch sum。

watch <expr>为表达式(变量)expr设置一个观察点,一量表达式值有变化时,程序会停止执行。
要观查当前设置的watch,可以使用info watchpoints命令。
next、step命令:
next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Old value和New value)。
next、step命令的区别在于step遇到函数调用,会跳转到到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作一条普通语句执行。
4.Make
make是所有想在Linux系统上编程的用户必须掌握的工具,对于任何稍具规模的程序,我们都会使用到make,几乎可以说不使用make的程序不具备任何实用价值。
在此,我们有必要解释编译和连接的区别。编译器使用源码文件来产生某种形式的目标文件(object files),在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。而连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。
编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程很痛苦,我们需要使用大量的gcc命令。
而make则使我们从大量源文件的编译和连接工作中解放出来,综合为一步完成。GNU Make的主要工作是读进一个文本文件,称为makefile。这个文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。
假设我们写下如下的三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数:
/* filename:add.h */
extern int add(int i, int j);

/* filename:add.c */
int add(int i, int j)
{
  return i + j;
}

/* filename:main.c */
#include "add.h"
main()
{
  int a, b;
  a = 2;
  b = 3;
  printf("the sum of a+b is %d", add(a + b));
}
怎样为上述三个文件产生makefile呢?如下:
test : main.o add.o
gcc main.o add.o -o test
     
main.o : main.c add.h
gcc -c main.c -o main.o
     
add.o : add.c add.h
gcc -c add.c -o add.o 
上述makefile利用add.c和add.h文件执行gcc -c add.c -o add.o命令产生add.o目标代码,利用main.c和add.h文件执行gcc -c main.c -o main.o命令产生main.o目标代码,最后利用main.o和add.o文件(两个模块的目标代码)执行gcc main.o add.o -o test命令产生可执行文件test。
我们可在makefile中加入变量,另外。环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。Make变量可以做很多事情,例如:
i) 存储一个文件名列表; 
ii) 存储可执行文件名; 
iii) 存储编译器选项。 
要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量名)。我们把前面的 makefile 利用变量重写一遍(并假设使用-Wall -O –g编译选项):      
OBJS = main.o add.o 
CC = gcc 
CFLAGS = -Wall -O -g
     
test : $(OBJS)
$(CC) $(OBJS) -o test
     
main.o : main.c add.h
$(CC) $(CFLAGS) -c main.c -o main.o 
     
add.o : add.c add.h 
$(CC) $(CFLAGS) -c add.c -o add.o 
makefile 中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码: 
clean: 
rm -f *.o
运行make clean时,将执行rm -f *.o命令,删除所有编译过程中产生的中间文件。
不管怎么说,自己动手编写makefile仍然是很复杂和烦琐的,而且很容易出错。因此,GNU也为我们提供了Automake和Autoconf来辅助快速自动产生makefile,读者可以参阅相关资料。
5.小结
本章主要阐述了Linux程序的编写、编译、调试方法及make,实际上就是引导读者学习怎样在Linux下编程,为后续章节做好准备。

转载于:https://blog.51cto.com/kkk110/979983

LINUX下的C编程实战(一)――开发平台搭建相关推荐

  1. Linux下的C编程实战(开发平台搭建,文件系统编程,进程控制与进程通信编程,“线程”控制与“线程”通信编程,驱动程序设计,专家问答)

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来,Linux ...

  2. Linux下的C编程实战

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...

  3. Linux下的C编程实战(转载)

    http://www.cnblogs.com/alexusli/archive/2008/10/24/1318736.html Linux下的C编程实战(转载) (转自)http://www.cnbl ...

  4. c 调用 linux驱动程序,Linux下的C编程实战(五)――驱动程序设计

    Linux下的C编程实战(五) ――驱动程序设计 1.引言 设备驱动程序是操作系统内核和机器硬件之间的接口,它为应用程序屏蔽硬件的细节,一般来说,Linux的设备驱动程序需要完成如下功能: (1)初始 ...

  5. Linux下的C编程实战之文件系统编程

    在Linux平台下对文件编程可以使用两类函数:(1)Linux操作系统文件API:(2)C语言I/O库函数.前者依赖于Linux系统调用,后者实际上与操作系统是独立的,因为在任何操作系统下,使用C语言 ...

  6. Linux下ACE、xml解析库开发环境搭建

    一.安装环境   1.安装vmware12.0版本 2.安装centos6.6的镜像文件 3.安装vmare_tool工具(方便虚拟机与实体机的切换) 4.配置网络      虚拟机网络连接方式:桥接 ...

  7. Linux下C语言编程-进程的创建

    Linux下C语言编程-进程的创建 作者:hoyt 1.进程的概念 Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命令.那么操作系统是怎么实现多用户的环境呢?在现代的操作 ...

  8. linux+下c语言编程项目,精通UNIX下C语言编程与项目实践

    cc -I  //include 目录 -L //静态库目录?动态也可以 -l //小写L,接静态库名称?动态也可以 -DXXX='"XXFF"' //-D直接定义宏 -c 只编译 ...

  9. 您知道Linux下C语言编程的一些注意事项吗_教育中国

    您知道Linux下C语言编程的一些注意事项吗_教育中国 云风的 BLOG: 一个 C 接口设计的问题 一个 C 接口设计的问题 C 语言在本质上,参数传递都是值传递.不像 Pascal 和 C++ 可 ...

  10. Linux下TCP网络编程-创建服务器与客户端

    一.前言 互联网概念诞生于20世纪60年代末,从9几年中国接入互联网开始到现在,生活的每个角落都能看到网络的使用.现在物联网时代.共享经济的到来,生活中不仅仅电脑.手机可以接入网络,身边的各个设备也能 ...

最新文章

  1. 理解java和python类变量以及类的成员变量
  2. Spring mvc集成log4j2
  3. python编程语言是什么-Python编程语言的特点是什么?老男孩Python学习
  4. 离散数学 第二章 谓词逻辑 2-1 谓词的概念与表示
  5. Mantle For iOS
  6. 基于大数据的房价数据可视化分析预测系统
  7. 阵列信号处理基础(一、协方差矩阵)
  8. 在线问诊第一平台微医引入智齿 构建智慧客服体系
  9. Windows系统电脑常用快捷键
  10. linux内核态延时函数及头文件,Linux内核延时函数
  11. UEFI Boot Flow 系列之 SEC Phase
  12. java findLoadedClass实践
  13. 存储基础:DAS/NAS/SAN存储类型及应用
  14. uboot启动之BL2阶段的分析1:宏观分析
  15. 尽信书则不如无书、尽信标准则不如无标准(也谈JM8.6代码中的手误)
  16. 星力+手游运营版本完整版打包下载 代理+服务端+后台+更新+APP
  17. 你所不知道的几个QQ空间技巧大全
  18. 圣诞 贺卡音乐礼盒杰理AD142A4
  19. 前端内卷加速破局之道
  20. 6《小学数学教材解读策略研究》教师问卷

热门文章

  1. 线性空间与坐标空间的同构
  2. trace (矩阵的迹) 的性质
  3. 向量函数具有固定模的充要条件
  4. Windows 7下IE 11的F12控制台不能使用的解决
  5. 脏读、不可重复读与幻读和spring事务传播方式
  6. linux三剑客之sed命令,linux三剑客之sed命令
  7. mysql删除的方法_mysql三种删除方式
  8. maven创建web工程,完善目录结构时出现HttpServlet等类的找不到的bug
  9. QueryWrapper、LambdaQueryWrapper以及LambdaQueryChainWrapper用法
  10. 使用ifconfig命令来看网卡的IP,但是,输入命令之后,eht0里面只有 inet6 addr 而没有 inet addr...