学会了GDB,就像山顶洞人学会了钻木取火

我们在编程的时候,很少能一次性写成并能成功运行,期间会出现很多错误,其中语法错误并不可怕,因为编译器会检测出来并提示我们哪里有错,最让code monkey头疼的应该就是语义错误了,因为他能通过编译器产生目标代码,但是结果就是不对,升值出现一些很严重的错误-段错误,这些错误往往不是轻易的一眼就能看出来的,那么我们要怎么调试呢?在linux下有一个非常强大的调试工具GDB。让语义错误现出原形。废话不多说,下面就是GDB的用法及指令:

首先gdb调试的是目标程序, 而不是源代码,所以编译时要加上 -g 选项,生成的可执行文件才能用gdb调试。

如:gcc -g test.c -o test

然后就可以进行调试了:gdb test 启动gdb后(还有一种启动方式就是输入:gdb回车之后再用file + 文件名转入调试程序,只会一种即可),首先显示一段版权说明,这段完全不用去理会(如果不想看到这些可以再启动的时候加上-q选项 如:gdb -q test),然后是gdb的提示符(gdb),可以再其后输入调试命令!quit命令推出调试。有事会出现 the program is runing. eexit anyway?(y or n)这是提示信息,表示程序正在运行过程中,是否强行推出,输入y即可退出。

1.显示和查找程序云代码:

->list:显示10行代码,若再次运行该命令,则显示接下来的10行代码。(执行完一条命令后,直接回车,默认执行上一条指令);

->list 5, 10:显示第5行到第10行的代码。

->list test.c:5, 10:显示源文件test.c文件的第五行到第十行代码,用于调试多个文件的程序时使用。

->lis main:显示mian函数周围的代码。

->list test.c:main:显示text.c中的main函数周围的代码。

如果想在调试过程中运行linux命令,可以再gdb的提示符下面输入shell命令。如:shell ls

->search + 字符串:从当前航向后超找第一个匹配的字符串,forward命令和他功能一样,用法也一样。如:search main找到mian所在位置。

->reverse-search 字符串:表示向前查找。

2.执行程序和获得帮助

使用gdb -q test只是装入程序,程序并没有运行,如果要是程序运行,要用start命令,开始执行程序,gdb停在main函数中定义变量之后的第一条语句出等待我们发命令,也可以直接输入run命令。如果想要了解某个命令的用法,可以使用help命令。如:help list,在如:help all。

3.设置断点和管理断点。

  1)一行好设置断点,gdb中,大部分使用break命令为程序设置断点。而指定断点时,最常使用的是为某行设置断点。如:break 7。之后会显示:breakpoint 1 at 0x******:file test.c, line 7.这一行是反馈信息,1表示当前设置的是第一个断点,0x******是断点所在的内存地址, file test.cline 7表明断点设置在test.c的第七行。然后输入run命令程序开始执行,并且程序执行完第六行的指令就停下来,并且打印出第七行的指令。

  2)以函数名设置断点,break后面跟上函数名就可以为函数设置断点。 break get_sum,然后在run就会停在get_sum函数那里。

  3)以条件表达式设置断点。格式为:break 行号或者函数名 if 条件;如:break 7 if i == 99;i=99时,程序中断在第七行。含有一种设置断点的方法,这种设置方式不需要制定行号或者函数名,而在整个运行过程中,当条件表达式的值发生改变的时候程序就会停下来。命令格式是:watch 条件表达式;如上面的例子就可以直接写为:watch i == 99.

  4)查看当前设置的断点,使用命令:info breakpoints(用table可以补齐),会显示一些中断的信息,NUM表示断点的编号,Type指明类型,Disp指示中断在生效一次后是否失去作用,如果是则为dis,不是这位keep,Enb表示当前断点是否有效,如果是为y,否为n。Address列表示中断处所在的内存地址。what表示中断发生在哪个函数,第几行。“stop only if result == 5050”表明这是一个条件中断。

  5)使中断失效或者有效。disable 2:是2号中断无效,使用info breakpoints查看一下,Enb列变为n。使其重新有效命令为:enable 2.

  6)删除断点,disable指示让断点失效,断点依然存在于程序中,如果要删除断点,可以用clear或者delete命令:

    ->clear:删除所有断点。

    ->clear 行号:删除此行的断点,删除以函数名作为断点的方法也是一样,把行号改为函数名即可,如:clear get_num。

    ->delete 断点编号:删除指定编号的断点,如果一定要删除多个断点,各个断点号以空格隔开。delete 2 3;

4.查看和设置变量的值。

  1)print命令, print 变量名或表达式:打印变量或者表达式的值;

         print 变量=值:对变量进行赋值;

         print 表达式@要打印的值的个数n:打印以表达式开始的n个数;

  2)whatis命令:显示变量或者表达式的数据类型;如 whatis i 显示type = int

  3)set命令:格式:set variable 变量=值:为变量赋值。print i = 200和set variable i= 200的功能是一样的。

5.控制程序的执行

  1)continus命令,让程序继续运行,知道下一个断点或者运行完为止。无参数,直接输入即可。

  2)kill命令:用于结束当前调试,使用时会询问是否退出程序调试,输入y即可。

  3)next和step单步执行,next会将函数调用当成一条语句执行过去,不进入函数中,step函数进入函数内部。

  4)nexti和stepi命令:用来单步执行一条极其指令,注意不是执行一条语句,单步执行一条语句命令式next和step,如for(i = 0; i < n ; i++);这一条语句,要多条nexti才能执行完。

上面这些是最基本的命令和最常用到的命令,一般用这些指令就可以调试出大部分的予以错误。需要注意的是上面的几乎所有的命令都有简写形式,多数为首字母,如print简写为p。

面一些命令用于调试特殊错误:

backtrace命令(简写为bt)可查看函数调用的栈帧:显示下面信息

#0 add_rang(low= 1, high = 10) at main.c6

#1 0x******** in main() at main.c:14

信息内容为,add_range函数被main函数调用的,main传进来的参数是low = 1, high = 10.main函数的栈帧号为1,add_range的栈帧编号为0.

ifo命令:(简写为i),显示局部变量的值。

frame命令:(简写为f)选择栈帧;和info搭配使用,可以先选择栈帧号,然后显示其中的局部变量。 

display命令:用来跟踪变量,使得每次停下来都显示变量的值,如:display sum每次程序停下来都显示sun的值。

undisplay命令:取消跟踪。undisplay 1取消一号跟踪

watch命令,设置观察点 如:watch a[7]观察数组第八个元素。

info watchpoints命令 显示所有观察点  。

x命令:从某个位置开始打印存储单元的内容,全部当成字节来看,而且不区分哪个字节属于哪个变量。如:x/7b a(a为数组名),b表示每个字节一组,7表示打印七组。

最后:段错误并不可怕。

学会了上面的指示后,来调试段错误的时候就很容易了,加载程序之后直接运行,遇到段错误的时候程序会自动停下来,并且显示提示信息,也就是在那出现段错误。然后在会程序中找出错误并改正就好了。不过需要注意一点:如果某个函数的局部变量发生越界访问,有可能不立即产生段错误,而是在函数返回的时候产生段错误。

posted on 2012-06-02 09:09  蒋少  阅读(518)  评论(0编辑  收藏  举报

导航