1、第五讲Linux操作系统环境下的C程序开发技术主要内容编译器GCC简介编译器GCC使用make工具使用程序调试教学要求理解GCC概念;掌握GCC使用方法;学会编写makefile;掌握GDB调试方法。GCC简介名称:GNU project C and C+piler GNU piler Collection 管理与维护GNU项目 GCC简介GCC能工作在多种平台上Intel x86(Linux,Windows)Alpha(Linux)PowerPC(AIX)Sparc(Solaris)GCC可以编译多种语言 CC+Objective-C(标准C得派生)FortranJavaAda GCC简介C
2、语言编译过程 预处理阶段(Preprocess)“#”开头得指令(伪指令/宏指令)与特殊符号进行处理。编译阶段(pile)预处理之后得输出文件进行词法分析与语法分析汇编过程(Assemble)把汇编语言代码翻译成目标机器代码连接阶段(Link)解决外部符号访问地址问题(库函数)GCC得使用gcc 选项 输入文件输入文件包括源程序文件、编译中间文件等如果没有指定选项,Linux下生成得可执行文件就是a、outgcc得选项主要分为四组:预处理选项编译选项优化选项连接选项GCC得常用选项gcc常用选项选项含义-o file 将经过gcc处理过得结果存为文件file,这个结果文件可能就是预处理文件、汇
3、编文件、目标文件或者最终得可执行文件。假设被处理得源文件为source、c,如果这个选项被省略了,那么生成得可执行文件默认名称为a、out;目标文件默认名为source、o;汇编文件默认名为source、s;生成得预处理文件则发送到标准输出设备。GCC得常用选项gcc常用选项选项含义-c仅对源文件进行编译,不链接生成可执行文件。在对源文件进行查错时,或只需产生目标文件时可以使用该选项。-ggdb在可执行文件中加入调试信息,方便进行程序得调试。如果使用中括号中得选项,表示加入gdb扩展得调试信息,方便使用gdb来进行调试-O0、1、2、3对生成得代码使用优化,中括号中为优化级别,缺省得情况为2级
4、优化,0为不进行优化。注意,采用更高级得优化并不一定得到效率更高得代码。-Dname=definition将名为name得宏定义为definition,如果中括号中得部分缺省,则宏被定义为110大家应该也有点累了,稍作休息大家有疑问得大家有疑问得大家有疑问得大家有疑问得,可以询问与交流可以询问与交流可以询问与交流可以询问与交流GCC得常用选项gcc常用选项选项含义-Idir在编译源程序时增加一个搜索头文件得额外目录dir,即include增加一个搜索得额外目录。-Ldir在编译源文件时增加一个搜索库文件得额外目录dir-llibrary在编译链接文件时增加一个额外得库,库名为library、a
5、-w禁止所有警告-Wwarning允许产生warning类型得警告,warning可以就是:main、unused等很多取值,最常用就是-Wall,表示产生所有警告。如果warning取值为error,其含义就是将所有警告作为错误(error),即出现警告就停止编译。GCC文件扩展名规范 gcc文件扩展名规范扩展名类型可进行得操作方式、cc语言源程序预处理、编译、汇编、链接、C,、cc,、cp,、cpp,、c+,、cxxc+语言源程序预处理、编译、汇编、链接、i预处理后得c语言源程序编译、汇编、链接、ii预处理后得c+语言源程序编译、汇编、链接、s预处理后得汇编程序汇编、链接、S未预处理得汇编
6、程序预处理、汇编、链接、h头文件不进行任何操作、o目标文件链接使用gcc编译代码源代码示例源程序示例源程序hello、c#include int main(void)printf(hello gcc!rn);return 0;生成预处理文件$gcc E hello、c o hello、i预处理文件预处理文件hello、i得部分内容得部分内容、extern void funlockfile(FILE*_stream);#679/usr/include/stdio、h 3#2 hello、c 2int main(void)printf(hello gcc!n);return 0;生成汇编文件$gc
7、c S hello、c o hello、s汇编文件汇编文件hello、s得部分内容得部分内容、main:pushl%ebpmovl%esp,%ebp、addl$16,%espmovl$0,%eaxleaveret、生成二进制文件生成目标文件命令:$gcc c hello、c o hello、o生成可执行文件命令:$gcc hello、c o hello运行程序$、/hellohello gcc!编译多个文件greeting、h#ifndef _GREETING_H#define _GREETING_Hvoid greeting(char*name);#endif greeting、c#incl
8、ude#include greeting、hvoid greeting(char*name)printf(Hello%s!rn,name);my_app、c#include#include greeting、h#define N 10int main(void)char nameN;printf(Your Name,Please:);scanf(%s,name);greeting(name);return 0;编译多个文件目录结构(1)编译命令$gcc my_app、c greeting、c o my_app目录结构(2)编译方式(1)$gcc my_app、c functions/greet
9、ing、c o my_app -I functions greeting.h./greeting.cmy_app.cgreeting.h./greeting.cmy_app.cfunctions编译多个文件目录结构(2)编译方式(2)分步编译命令:1、$gcc -c my_app、c -I functions 2、$gcc -c functions/greeting、c3、$gcc my_app、o greeting、o o my_app思路:编译每一个、c文件,得到、o得目标文件;将每一个、o得目标文件链接成一个可执行得文件;使用make工具适用场合:多个文件组成得软件项目基本格式:目标:欲
10、生成得目标文件依赖项:生成目标需要得文件原理:判断依赖项就是否为最新,否则,生成新得目标目标目标:依赖项列表依赖项列表(Tab缩进缩进)命令命令使用make工具make工具得使用格式:make 命令选项 命令参数通常使用make就可以了,make会寻找Makefile作为编译指导文件;使用make工具Makefile示例Makefile文件1my_app:greeting、o my_app、o2gcc my_app、o greeting、o-o my_app3greeting、o:functions/greeting、c functions/greeting、h4gcc-c functions
11、/greeting、c5my_app、o:my_app、c functions/greeting、h6gcc c my_app、c Ifunctions使用make工具目标得依赖关系my_appmy_app.ogreeting.omy_app.cfunctions/greeting.hfunctions/greeting.cgcc c my_app.c Ifunctions gcc-c functions/greeting.c gcc my_app.o greeting.o-o my_app 使用make工具更实用得Makefile文件1OBJS=greeting、o my_app、o2CC=
12、gcc3CFLAGS=-Wall-O g4my_app:$OBJS5$CC$OBJS-o my_app6greeting、o:functions/greeting、c functions/greeting、h7$CC$CFLAGS-c functions/greeting、c8my_app、o:my_app、c functions/greeting、h9$CC$CFLAGS-c my_app、c-Ifunctionstarget:$OBJ gcc -o target clean:rm install:remove:Makefile实例调试静态调试在程序编译阶段查错并修正错误;主要为语法错误:输
13、入错误;类型匹配错误;排错方式:利用错误、警告信息,并结合源文件环境排错静态调试举例动态调试:在程序运行阶段差错并修正错误;主要错误类型:算法错误;输入错误;排错方式:利用调试工具定位并修正错误;静态调试举例greeting、h#ifndef _GREETING_H#define _GREETING_Hvoid greeting(char*name);#endif greeting、c#include#include greeting、hvoid greeting(char*name)printf(Hello!rn);my_app、c 1#include 2#include greeting、
14、h3#define N 104 int main(void)5 6 char namen;7 printf(Your Name,Please:);8 scanf(%s,name)9 greeting(name);10/*return 0;*/11 静态调试举例分块编译greeting、c$gcc -g -Wall -c functions/greeting、c-g:将调试信息加入到编译得目标文件中;-Wall:将编译过程中得所有级别得警告都打印出来;无错误my_app、c$gcc -g -Wall -c my_app、c -Ifunctions参数含义同上错误信息:静态调试举例错误信息:错误记
15、录格式:文件名:行号:错误描述my_app、c:In function main:my_app、c:6:n undeclared(first use in this function)my_app、c:6:(Each undeclared identifier is reported only oncemy_app、c:6:for each function it appears in、)my_app、c:9:parse error before greetingmy_app、c:6:warning:unused variable name静态调试举例分析、定位错误(警告):my_app、c得
16、第6行:描述含义:n就是一个没有声明得变量;分析:声明数字name时用到了变量n,但变量n在之前没有声明;改正:声明一个新变量n;或者将n改为宏N这里取第2种改正方法;静态调试举例my_app、c得第9行:描述含义:在“greeting”之前出现解析错误;分析:c中每行程序以;结束,第9行greeting之前得程序行没有以;结束;改正:第8行末尾增加“;”重新编译错误信息:my_app、c:In function main:my_app、c:11:warning:control reaches end of non-void function静态调试举例分析、定位错误(警告):警告:my_ap
17、p、c得11行描述含义:控制以非空函数结束;分析:main函数返回类型为int,源程序没有以return 整数形式结束;改正:将main改为返回void类型;或者:在main程序后增加return 返回语句;采用第2种解决方式;重新编译,无错误或警告信息,完成静态调试静态调试举例静态调试总结主要为语法错误:输入错误;类型匹配错误;分析信息:主要来自gcc编译时产生得提示信息错误警告定位:不一定在提示信息描述得地方;综合分析提示信息及提示行得上下文环境,定位并修正错误、警告。有得警告可以不用修复。动态调试 常见得动态调试方法:增加调试语句;记录程序得执行状况;观察内存变化;使用调试工具;GNU
18、Debuger得功能:启动程序,设置程序执行得上下文环境;在指定得条件下停止程序;程序停止时,检查程序得状态;在程序运行时,改变程序状态,使其按照改变后得状态继续执行。GDB得使用基本命令显示源程序查瞧运行时数据改变与显示目录或路径控制程序得执行其她命令获得帮助启动gdb后使用help命令GDB得使用gdb常用得调试命令命令含义file指定需要进行调试得程序指定需要进行调试得程序step单步单步(行行)执行执行,如果遇到函数会进入函数内部如果遇到函数会进入函数内部next单步单步(行行)执行执行,如果遇到函数不会进入函数内部如果遇到函数不会进入函数内部run启动被执行得程序启动被执行得程序qu
19、it退出退出gdb调试环境调试环境print查瞧变量或者表达式得值查瞧变量或者表达式得值break设置断点设置断点,程序执行到断点就会暂停起来程序执行到断点就会暂停起来shell执行其后得执行其后得shell命令命令list查瞧指定文件或者函数得源代码查瞧指定文件或者函数得源代码,并标出行号并标出行号GDB得使用显示源程序Listlist 显示当前行后面得程序list-显示当前行前面得程序list file:linenum 显示linenum行周围得程序list startline,endline list file:function 显示函数名为function得程序show listsiz
20、e 显示listsize设置set listsize num 设置listsize设置源代码搜索forward-search,search,reverse-searchGDB得使用查瞧运行时数据print p(p为变量名)print function(1,0)print*p whatis pGDB得使用改变与显示目录与路径directorycdpathpwdshow directoriesshow pathGDB得使用控制程序得执行设置/显示断点break,info break维护断点delete breakpoint;delete breakpoint 1;enable/disable br
21、eakpoint 1;clear linenum;运行程序run单步调试与连续执行step,next,continue函数调用call,returnGDB得使用其她命令执行shell命令其格式就是:shell mand-string修改变量值print x=10set variable x=10跳转执行jump linenumjump *addr 动态调试举例对静态调试中得例子继续进行动态调试工具:gdb启动gdb$gdbGNU gdb Red Hat Linux(5.3post-0.20021129.18rh)Copyright 2003 Free Software Foundation,I
22、nc.GDB is free software,covered by the GNU General Public License,and you arewelcome to change it and/or distribute copies of it under certain conditions.Type show copying to see the conditions.There is absolutely no warranty for GDB.Type show warranty for details.This GDB was configured as i386-red
23、hat-linux-gnu.(gdb)启动命令启动命令启动提示启动提示启动完毕启动完毕动态调试举例调试指定程序(、/my_app)问题:期望得输出与实际输出不一致(gdb)Reading symbols from./my_app.done(gdb)runStarting program:/home/tom/shell_script/cpp/my_app/my_appYour Name,Please:tomHello!Program exited normally.(gdb)加载调试程序加载调试程序启动调试程序启动调试程序程序输出程序输出提示信息提示信息动态调试举例初次错误定位:输出有错误错误定
24、位重新开始一次调试;启动gdb;加载调试程序(、/my_app);查瞧程序源代码命令:list 文件名动态调试举例(gdb)list my_app、c:1,201#include 2#include greeting、h3#define N 104int main(void)56char nameN;7printf(Your Name,Please:);8scanf(%s,name);9greeting(name);10return 0;11(gdb)break 7BreakPoint 1 at 0 x8048384:,line 7、在程序第7行设置断点命令:(gdb)break 7查看源代码
25、查看源代码设置断点设置断点提示信息提示信息动态调试举例错误详细定位1(gdb)run2Starting program:/home/tom/shell_script/cpp/my_app/my_app3Breakpoint 1,main()at my_app、c:747printf(Your Name,Please:);5(gdb)next68 scanf(%s,name);7(gdb)next8Your Name,Please:tom99 greeting(name);启动调试程序启动调试程序断点激活断点激活步进下一步步进下一步动态调试举例10(gdb)print name11$1=“tom
26、00000012(gdb)step13greeting(name=0 xbfffdf20“tom”)at functions/greeting、c:5145 printf(”Hello!rn”);15(gdb)step16Hello!176 18(gdb)kill19Kill the programe being debugged?(y or n)y20(gdb)quit查看变量值查看变量值进入函数内部进入函数内部步进执行步进执行停止调试停止调试退出退出gdb动态调试举例分析:11行说明name变量被正确赋值(tom)13行说明name变量值被正确赋予greeting得参数变量name16说明
27、打印出现了错误,即错误出现在函数greeting中;综合分析错误出现在greeting、c得第5行;原因:没有输出字符串得格式不对;改正错误动态调试举例动态调试总结主要错误类型:算法错误;输入错误;定位方法:设置断点;单步步进执行;查瞧变量取值变化;反复执行,逐步缩小错误范围;动态调试举例#include#include#define BIGNUM 1000void index_m(int ary,float fary);int main()int intary100;float fltary100;index_m(intary,fltary);exit(EXIT_SUCCESS);void
28、index_m(int ary,float fary)int i;float f=3、14;for(i=0;iBIGNUM;+i)aryi=i;faryi=i*f;动态调试举例使用gcc-g选项编译dbme、c调试dbme运行dbme列出源代码打印变量单步调试设置断点动态调试举例调试一个二进制代码得本地溢出程序overflow、c#include#include char largebuff=“1234512345123451=ABCD”;int main(void)char smallbuff16;strcpy(smallbuff,largebuff);动态调试举例调试overflow运行overflow单步调试列出汇编代码列出内存状况小结GCC使用方法makefile编写方法GDB使用方法作业练习makefile编写练习gdb调试