调试程序的基本思想是 : 分析现象 –》 假设错误出现的原因 –》 产生新的现象去验证假设
问题代码#includeint add_range(int low, int high){ int i, sum; for (i=low; i<=high; i++) sum = sum + i; return sum;}int main(void){ int result[100]; result[0] = add_range(1, 10); result[1] = add_range(1, 100); printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]); return 0;}
编译时,必须使用参数 -g,生成可执行文件,之后才能使用gdb调试
以上是,gcc –Wall –W –g gdb1.c –o gbd1
然后,gdb gbd1 ( 用gdb调试可执行文件 )
help –》 可以进一步 例如 help files 查看帮助list 1 从第一行显示,10行为单位,继续只需要 list,就可以继续显示,期间技巧是,之间敲回车,就是执行之前的命令,例如先敲 list ,之后直接敲回车,就会继续执行 list,缩写 l 。list行号列出从第几行开始的源代码。list 函数名 列出某个函数的源代码。
quit 退出环境,缩写 q
把源代码改名或移动到别处再调用gdb调试,这样就列不出源代码了。可见,调试时,虽然调试的是可执行文件,但是,也是需要源文件的。
start 开始执行
next 继续执行,缩写 n
step 进入调用函数内容,缩写 s,也是继续执行,只是碰到函数要进入内部。
backtrace 查看函数调用的栈,缩写 bt
info 查看局部变量,缩写 i , 例如 i locals 查看本地变量值
frame 变更当前堆栈,例如你在一个函数中,你想查看main函数中的变量的内容,则需要先变更当前堆栈,简写为 f,例如 f 1 (通过 bt 可以知道堆栈号,当前main函数堆栈号时 1 )
finish 运行到当前函数返回为止
set var sum=0 直接在gdb中修改 sum的值。还可以使用 print命令修改值,print 命令后面跟的是表达式,而且函数也是表达式,所以可以通过 print修改变量的值或者调用函数,缩写是 p
断点
display sum 每次停下来时,都显示 sum,undisplay命令可以取消显示,此时要给一个参数,就是第几个变量不想继续显示了,例如 undisplay 1
break 命令,设置断点,简写 b,可以在循环外设置断点,然后不需要继续执行循环时,直接跳到断点。例如 b 9 在第9行设置断点,b的参数也可以是函数名,表示在某个函数开头设置断点。然后可以使用continue简写 c , 继续执行,而非进入到 for 循环中,程序到断点会自动停下,可见,断点可以跳过没有问题的代码。i breakpoints 查看设置断点的信息,delete breakpoints 2,删除断点。先不用又不想删除的断点,可以禁用,disable breakpoints 3,启用的话,直接 enable 3,就可以了。禁用的断点会有标记(Enb) n ,之前可用的状态是 y,断点设置非常灵活,可以设置断点在满足某个条件时才激活,例如仅当 sum不等于0时菜终端, break 9 if sum != 0 , run 另可以从新从头执行程序,简写 r 。
观察点
x 命令打印指定存储单元的内容, x/7b input , 7b代表打印格式,b表示每个字节一组,7表示打印7组,观察点是当程序访问某个存储单元时中断,如果我们不知道某个存储单元时在哪里被改动的,这时候观察点尤其有用。watch 设置观察点,例如:watch input[5],i watchpoints 查看观察点信息,同样使用 c 继续执行到观察点。
段错误
段错误#includeint main(void){ int man = 0; scanf("%d", man); return 0;}
gdb会提示段错误,一般情况下,编译的时候 –Wall –W 参数使用后,会发现段错误。