您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > Linux C 编程
Linux下的C编程实战一开发工具链的使用1.引言Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性。而近年来,Linux操作系统在嵌入式系统领域的延伸也可谓是如日中天,许多版本的嵌入式Linux系统被开发出来,如ucLinux、RTLinux、ARM-Linux等等。在嵌入式操作系统方面,Linux的地位是不容怀疑的,它开源、它包含TCP/IP协议栈、它易集成GUI。鉴于Linux操作系统在服务器和嵌入式系统领域愈来愈广泛的应用,社会上越来越需要基于Linux操作系统进行编程的开发人员。笔者建议要直接安装Linux操作系统,如下图:在Linux平台下,可用任意一个文本编辑工具编辑源代码,但笔者建议使用emacs软件,它具备语法高亮、版本控制等附带功能,如下图:2.GCC编译器GCC是Linux平台下昀重要的开发工具,它是GNU的C和C++编译器,其基本用法为:gcc[options][filenames]options为编译选项,GCC总共提供的编译选项超过100个,但只有少数几个会被频繁使用,我们仅对几个常用选项进行介绍。假设我们编译一输出“HelloWorld”的程序:/*Filename:helloworld.c*/main(){printf(HelloWorld\n);}昀简单的编译方法是不指定任何编译选项:gcchelloworld.c它会为目标程序生成默认的文件名a.out,我们可用-o编译选项来为将产生的可执行文件指定一个文件名来代替a.out。例如,将上述名为helloworld.c的C程序编译为名叫helloworld的可执行文件,需要输入如下命令:gcc–ohelloworldhelloworld.c-c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤;-S编译选项告诉GCC在为C代码产生了汇编语言文件后停止编译。GCC产生的汇编语言文件的缺省扩展名是.s,上述程序运行如下命令:gcc–Shelloworld.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:终止gdbwatch:监视一个变量的值break:在代码里设置断点,程序执行到这里时挂起make:不退出gdb而重新产生可执行文件shell:不离开gdb而执行shell下面我们来演示怎样用GDB来调试一个求0+1+2+3+…+99的程序:/*Filename:sum.c*/main(){inti,sum;sum=0;for(i=0;i100;i++){sum+=i;}printf(thesumof1+2+...+is%d,sum);}执行如下命令编译sum.c(加-g选项产生debug信息):gcc–g–osumsum.c在命令行上键入gdbsum并按回车键就可以开始调试sum了,再运行run命令执行sum,屏幕上将看到如下内容:list命令:list命令用于列出源代码,对上述程序两次运行list,将出现如下画面(源代码被标行号):根据列出的源程序,如果我们将断点设置在第5行,只需在gdb命令行提示符下键入如下命令设置断点:(gdb)break5,执行情况如下图:这个时候我们再run,程序会停止在第5行,如下图:设置断点的另一种语法是breakfunction,它在进入指定函数(function)时停住。相反的,clear用于清除所有的已定义的断点,clearfunction清除设置在函数上的断点,clearlinenum则清除设置在指定行上的断点。watch命令:watch命令用于观查变量或表达式的值,我们观查sum变量只需要运行watchsum:watchexpr为表达式(变量)expr设置一个观察点,一量表达式值有变化时,程序会停止执行。要观查当前设置的watch,可以使用infowatchpoints命令。next、step命令:next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Oldvalue和Newvalue),如下图:next、step命令的区别在于step遇到函数调用,会跳转到到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作一条普通语句执行。4.Makemake是所有想在Linux系统上编程的用户必须掌握的工具,对于任何稍具规模的程序,我们都会使用到make,几乎可以说不使用make的程序不具备任何实用价值。在此,我们有必要解释编译和连接的区别。编译器使用源码文件来产生某种形式的目标文件(objectfiles),在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。而连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程很痛苦,我们需要使用大量的gcc命令。而make则使我们从大量源文件的编译和连接工作中解放出来,综合为一步完成。GNUMake的主要工作是读进一个文本文件,称为makefile。这个文件记录了哪些文件(目的文件,目的文件不一定是昀后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。假设我们写下如下的三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数:/*filename:add.h*/externintadd(inti,intj);/*filename:add.c*/intadd(inti,intj){returni+j;}/*filename:main.c*/#includeadd.hmain(){inta,b;a=2;b=3;printf(thesumofa+bis%d,add(a+b));}怎样为上述三个文件产生makefile呢?如下:test:main.oadd.ogccmain.oadd.o-otestmain.o:main.cadd.hgcc-cmain.c-omain.oadd.o:add.cadd.hgcc-cadd.c-oadd.o上述makefile利用add.c和add.h文件执行gcc-cadd.c-oadd.o命令产生add.o目标代码,利用main.c和add.h文件执行gcc-cmain.c-omain.o命令产生main.o目标代码,昀后利用main.o和add.o文件(两个模块的目标代码)执行gccmain.oadd.o-otest命令产生可执行文件test。我们可在makefile中加入变量,另外。环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。Make变量可以做很多事情,例如:i)存储一个文件名列表;ii)存储可执行文件名;iii)存储编译器选项。要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量名)。我们把前面的makefile利用变量重写一遍(并假设使用-Wall-O–g编译选项):OBJS=main.oadd.oCC=gccCFLAGS=-Wall-O-gtest:$(OBJS)$(CC)$(OBJS)-otestmain.o:main.cadd.h$(CC)$(CFLAGS)-cmain.c-omain.oadd.o:add.cadd.h$(CC)$(CFLAGS)-cadd.c-oadd.omakefile中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码:clean:rm-f*.o运行makeclean时,将执行rm-f*.o命令,删除所有编译过程中产生的中间文件。不管怎么说,自己动手编写makefile仍然是很复杂和烦琐的,而且很容易出错。因此,GNU也为我们提供了Automake和Autoconf来辅助快速自动产生makefile,读者可以参阅相关资料。5.小结本章主要阐述了Linux程序的编写、编译、调试方法及make,实际上就是引导读者学习怎样在Linux下编程,为后续章节做好准备。二文件系统编程1.Linux文件系统Linux支持多种文件系统,如ext、ext2、minix、iso9660、msdos、fat、vfat、nfs等。在这些具体文件系统的上层,Linux提供了虚拟文件系统(VFS)来统一它们的行为,虚拟文件系统为不同的文件系统与内核的通信提供了一致的接口。下图给出了Linux中文件系统的关系:在Linux平台下对文件编程可以使用两类函数:(1)Linux操作系统文件API;(2)C语言I/O库函数。前者依赖于Linux系统调用,后者实际上与操作系统是独立的,因为在任何操作系统下,使用C语言I/O库函数操作文件的方法都是相同的。本章将对这两种方法进行实例讲解。2.Linux文件APILinux的文件操作API涉及到创建、打开、读写和关闭文件。创建intcreat(constchar*filename,mode_tmode);参数mode指定新建文件的存取权限,它同umask一起决定文件的昀终权限(mode&umask),其中umask代表了文件在创建时需要去掉的一些存取权限。umask可通过系统调用umask()来改变:intumask(intnewmask);该调用将umask设置为newmask,然后返回旧的umask,它只影响读、写和执行权限。打开intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);open函数有两个形式,其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面),flags可以去下面的一个值或者是几个值的组合:标志含义O_RDONLY以只读的方式打开文件O_WRONLY以只写的方式打开文件O_RDWR以读写的方式打开文件O_APPEND以追加的方式打开文件O_CREAT创建一个文件O_EXEC如果使用了O_CREAT而且文件已经存在,就会发生一个错误O_NOBLOCK以非阻塞的方式打开一个文件O_TRUNC如果文件已经存在,则删除文件的内容O_RDONLY、O_WRONL
本文标题:Linux C 编程
链接地址:https://www.777doc.com/doc-5352471 .html