- gdb的命令都可以使用
help 命令
来查看如何使用 - 启动调试
gdb main
(main为可执行文件的名字) - 开始调试
start
常用的gdb调试命令:
命令 | 解释 |
---|---|
start | 开始执行程序,停在main函数第一行语句前面等待命令 |
list(或l) | 列出源代码,接着上次的位置往下列,每次列10行 |
list 行号 | 列出从第几行开始的源代码 |
list 函数名 | 列出某个函数的源代码 |
next(或n) | 执行下一行语句 |
step(或s) | 执行下一行语句,如果有函数调用则进入到函数中 |
backtrace(或bt) | 查看各级函数调用及参数 |
info(或i) | locals 查看当前栈帧局部变量的值 |
finish | 执行到当前函数返回,然后停下来等待命令 |
print(或p) | 打印表达式的值,通过表达式可以修改变量的值或者调用函数 |
frame(或f) | 帧编号 选择栈帧 |
set var | 修改变量的值 |
quit (q) | 结束调试 |
动手试一下吧(用上面的命令调试下面的这个程序):
任务
- 开始调试,并查看add_range函数
- 执行下一条语句
- 进入add_range(0, 10)函数内部,并查看函数调用的栈帧,和add_range的局部变量
- 循环中打印查看sum的值
- 结束当前函数调用,返回main函数
- 结束调试
1 | #include <stdio.h> |
设置断点
命令 | 解释 |
---|---|
break(或b) | 行号 在某一行设置断点 |
break 函数名 | 在某个函数开头设置断点 |
break…if… | 设置条件断点 |
continue(或c) | 从当前位置开始连续而非单步执行程序 |
delete breakpoints(断点的Num) | 删除断点 |
display 变量名 | 跟踪查看一个变量,每次停下来都显示它的值 |
disable breakpoints | 禁用断点 |
enable breakpoints | 启用断点 |
info(或i) breakpoints | 查看当前设置了哪些断点 |
run(或r) | 从头开始连续而非单步执行程序 |
undisplay | 取消对先前设置的那些变量的跟踪 |
动手试一下吧(用上面的命令调试下面的这个程序):
该程序预期实现将字符数字串
转为整型数字
,但是现在结果并不理想,请你找出bug并修复
任务
找出bug,实现预期功能
- 开始调试,并跟踪查看sum
- 在while(1)这一行设置一个断点
- 查看转换过程
- 查看已设置的断点
- 删除断点
1 | #include <stdio.h> |
观察点
接着上一节的调试,我们知道上节中bug在于在每次循环中,sum并没有赋初值,所以导致从第一次后,转换就出现bug。现改正为下面代码:
1 | #include <stdio.h> |
使用scanf函数是非常凶险的,即使修正了这个Bug还存在很多问题。如果输入的字符串超长了会怎么样?我们知道数组访问越界是不会检查的,所以scanf会写出界。(这个bug很容易修复,可以自己尝试一下)
提示:for的终止条件为’\0’,查看input元素(多查看几个,大于数组长度)寻找问题
这节,我们将学习一下监视点的使用
和如何查看内存
查看内存使用命令
examine
,简写为x
使用:$ x/(n,f,u为可选参数) 地址
n: 需要显示的内存单元个数,也就是从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义
f:显示格式
1
2
3
4
5
6
7
8x(hex) 按十六进制格式显示变量。
d(decimal) 按十进制格式显示变量。
u(unsigned decimal) 按十进制格式显示无符号整型。
o(octal) 按八进制格式显示变量。
t(binary) 按二进制格式显示变量。
a(address) 按十六进制格式显示变量。
c(char) 按字符格式显示变量。
f(float) 按浮点数格式显示变量u:每个单元的大小,按字节数来计算。默认是4 bytes。GDB会从指定内存地址开始读取指定字节,并把其当作一个值取出来,并使用格式f来显示
1
2
3b:1 byte
h:2 bytes
w:4 bytes g:8 bytes举例(用上面函数):
例子 解释 x/7b input
默认以10进制打印input开始,4个单元(每单元1byte) x/7cb input
按字符格式,打印input开始,4个单元(每单元1byte)
观察点
我们知道断点是当程序执行到某一代码行时中断,而观察点是当程序访问某一存储单元时中断。
有两种使用情况:
- 如果我们不知道某一存储单元是在哪里被改动的,这时候观察点尤其有用(直接
watch 变量名
) - 在不确定发生问题的地方时,通过使用观察点的条件表达式,可以非常方便地找出问题代码。(
watch i>99
)
其他相关命令:查看、删除、禁用、启用均与断点相同
- 如果我们不知道某一存储单元是在哪里被改动的,这时候观察点尤其有用(直接