使用GCC编译程序时,编译过程可以被细分为四个阶段:
在这四个阶段中可以设置选项分别生成扩展名分别为“.i”、“.s”、“.o”的文件,以及最终可执行文件,各扩展名文件含义如下:
.c
:最初的c源代码文件。.i
:经过编译预处理的源代码。.s
:汇编处理后的汇编代码。.o
:编译后的目标文件,含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义下面以程序hello.c为例具体看一下GCC是如何完成以上四个步骤的,程序hello.c源代码如下所示。
#include
int main(void)
{
printf("Hello World!/n");
return 0;
}
(1)预处理阶段
(2)编译阶段
$gcc -S hello.i -o hello.s
(3)汇编阶段
$gcc -c hello.s -o hello.o
(4)链接阶段
$gcc hello.o -o hello
格式:gcc [选项|文件]…
(1)总体选项
(2)链接选项
(3)警告选项
示例:
(1)编译当前目录下的文件helloworld.c。
$gcc helloworld.c
该命令将helloworld.c文件预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out,a.out为可执行程序文件名。
(2)将当前目录下的文件helloworld.c编译成名为helloworld的可执行文件。
$gcc –o helloworld helloworld.c
(3)将当前目录下的文件helloworld.c编译为汇编语言文件。
$gcc –S helloworld.c
该命令生成helloworld.c的汇编文件helloworld.s,使用的是AT&T汇编。
(4)将文件testfun.c 和文件test.c 编译成目标文件test
方法1:
$gcc testfun.c test.c -o test
方法2:
$gcc -c testfun.c //将testfun.c编译成testfun.o
$gcc -c test.c //将test.c编译成test.o
$gcc testfun.o test.o -o test //将testfun.o和test.o链接成test
(5)编译当前目录下的程序bad.c,同时查看编译过程中所有报警信息。
程序bad.c的源码如下所示。
#include
int main (void)
{
printf ("Two plus two is %f\n", 4);
return 0;
}
gdb是Linux系统中一个功能强大的GNU调试程序,它可以调试C和C++程序,使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。gdb提供如下功能:
1.启动gdb
要使用gdb调试程序,首先在编译时,必须把调试信息加到可执行文件中,可通过使用编译器gcc的 -g 参数完成。
如:$gcc -g hello.c -o hello
启动gdb的方法有以下四种:
(1)gdb
(2)gdb
(3)gdb
gdb同时调试可执行程序program和文件core,文件core是程序崩溃时产生的文件,仅仅是一个内存映象(加上调试信息),主要是用来调试的。
(4)gdb
PID是程序运行时的进程号,gdb会自动绑定到该进程上,并调试。
gdb可以用list(list指令可简写为l)命令来显示程序的源代码,其方法有如下几种:
(1)格式:list [file:]linenum
说明:显示程序file中的第linenum行周围的源代码。
(2)格式:list [file:]function
说明:显示程序file中的函数名为function的函数的源代码。
(3)格式:list
说明:显示当前行后面的源代码。
(4)格式:list –
说明:显示当前行前面的源代码。
(5)格式:list start,end
说明:显示从行号start到end之间的代码行。默认情况下,list命令显示10行代码。
gdb可用print (print 指令可简写为 p)命令来监视及更改变量值。
格式:
示例:
(1)显示变量a的内容。
(gdb) print a
(2)显示变量a的长度。
(gdb) print sizeof(a)
(3)将变量a的值设定为 10。
(gdb) print (a=10)
调试程序过程中,经常需要暂停程序的运行,以便查看某些变量值的变化,及程序运行的流程。gdb可以方便地暂停程序的运行,常用的有以下几种暂停方式:断点(BreakPoint)、观察点(WatchPoint)、捕捉点(CatchPoint)。如要恢复程序运行,可以使用c命令或是continue命令。
gdb用break命令来设置断点,设置断点的方法有如下几种:
(1)格式:break
说明:将程序在进入指定函数function时停住,function为函数名。
(2)格式:break
说明:将程序在指定行号linenum停住,linenum为行号。
(3)格式:break +offset
或break -offset
说明:将程序在当前行号的前面或后面的offset行停住,offiset为自然数。
(4)格式:break filename:linenum
说明:将程序在源文件filename的行号linenum处停住,filename为源文件名,linenum 为行号。
(5)格式:break filename:function
说明:将程序在源文件filename的function函数的入口处停住,filename为源文件名,function为函数名。
(6)格式:break *address
说明:将程序在运行的内存地址address处停住,address为程序运行的内存地址。
(7)格式:break
说明:将程序在下一条指令处停住。
(8)格式:break ... if
说明:将程序在条件condition成立停住,…表示上述的参数。
(9)格式:info breakpoints
说明:显示程序设置的所有断点。
观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化,如果有变化,马上停住程序。设置观察点的方法有以下几种:
(1)格式:watch
说明:为表达式expr设置一个观察点,当表达式的值有变化时,停住程序。
( 2)格式:rwatch
说明:为表达式expr设置一个观察点,当表达式的值被读时,停住程序。
(3)格式:awatch
说明:为表达式expr设置一个观察点,当表达式的值被读或被写时,停住程序。
可使用info命令显示程序中设置了哪些观察点,命令如下所示。
格式:info watchpoints
说明:显示程序设置的所有观察点。
在程序运行过程中,当发生了某些事件,如动态链接库加载、暂停程序运行等,可设置捕捉点来捕捉这些事件,暂停程序运行。用户可对事件作出分析判断,并采取相应措施。设置捕捉点命令如下所示。
格式:catch
说明:将程序在事件event发生时停住
在gdb中,可以使用delete、clear、disable、enable这几个命令进行维护。
(1)格式:clear
说明:清除所有的已定义的停止点。
(2)格式:clear
或clear
说明:清除所有设置在函数function上的停止点,或清除所有设置在源文件filename中函数function上的停止点。
(3)格式:clear
或clear
说明:清除所有设置在指定行linenum上的停止点,或清除所有设置在源文件filename中指定行linenum上的停止点。
linenum为行号,filename为源文件名。
(4)格式:delete [breakpoints] [range...]
说明:删除指定的断点。breakpoints为断点号,如果不指定断点号,表示删除所有的断点
(5)格式:disable [breakpoints] [range...]
说明:停用指定的断点。breakpoints为断点号,如果不指定断点号,表示停用所有的断点。停用的断点,gdb不会删除,需要时利用enable命令激活即可,简写命令是dis。
(6)格式:enable [breakpoints] [range...]
说明:激活指定的断点,breakpoints为断点号,如果不指定断点号,表示激活所有的断点。range 表示断点号的范围
使用gdb提供的command命令可设置停止点的运行命令。
格式:
commands [bnum] ... command-list ... end
说明:为断点号bnum指写一个命令列表command-list,当程序停在该断点时,gdb会依次运行命令列表中的命令。bnum为断点号,command-list为执行的命令列表。
设置好停止点后,就可以使用run命令运行程序。
格式:(gdb) run
说明:该命令表示从程序开头执行程序,直到遇到断点或是程序执行完毕为止。
程序被停住,可用continue命令恢复程序的运行直到程序结束,或下一个断点到来。
(1)格式:
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
说明:continue,c,fg三个命令功能基本相同。恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数。
(2)格式:step
说明:单步跟踪,count表示执行后面的count条指令后再停住,省略表示一条条执行。如果有函数调用,会进入该函数。进入函数的前提是,此函数被编译有debug信息。
(3)格式:next
说明:单步跟踪,count表示执行后面的count条指令后再停住,省略表示一条条执行。如果有函数调用,不会进入该函数。
(4)格式:set step-mode
或set step-mode on
说明:打开step-mode模式,进行单步跟踪时,程序不会因为没有debug信息而不停住。
(5)格式:set step-mod off
说明:关闭step-mode模式。
(6)格式:finish
说明:运行程序,直到当前函数完成返回。打印函数返回时的堆栈地址和返回值及参数值等信息。
(7)格式:until 或 u
说明:运行程序直到退出循环体,即取消在一个循环体内单步跟踪。
(8)格式:stepi
或 si
nexti
或 ni
说明:单步跟踪一条机器指令i,一条程序代码有可能由数条机器指令完成,step i和nexti可以单步执行机器指令。
打开可执行文件后,可根据需要在程序中加入断点或观察点,并运行程序。以helloworld程序为例,可在为变量赋值前加入断点,并运行程序。方法如下:
(gdb) break 5 // 在源代码第5行,即变量c赋值处加入断点
(gdb) run // 运行程序