3. GDB基本命令:run、continue、next、step、print、list、quit
调试器这东西,说白了就是让你能「看」着程序跑。GDB 最核心的几条命令,其实一只手就数得过来。我刚开始学的时候,就靠这七条命令撑过了大半个项目。你想想看,如果连程序都跑不起来,那还调试个啥?
3.1 run —— 让程序跑起来
run 命令,简写是 r。它的作用就是启动你正在调试的程序。如果你在启动 GDB 时没带参数,或者想重新跑一次,就用它。
基本用法:
(gdb) run
(gdb) r # 简写形式
(gdb) run arg1 arg2 # 带命令行参数启动
我个人习惯在启动 GDB 时先设好断点,然后再敲 run。这样程序一跑起来就会停在你想看的地方。如果你没设断点,那程序就直接跑完了——嗯,那就没调试什么事了。
小技巧:如果你忘了之前设过哪些断点,可以用 info breakpoints 查看。我经常这么干,因为年纪大了记性不好。
3.2 continue —— 继续跑,别停
continue,简写 c。当程序因为断点停下来后,你想让它继续往下跑,就用这个命令。
(gdb) continue
(gdb) c # 简写
我在项目中遇到过一种情况:一个死循环问题,我在循环体里设了断点,然后不停地 c,观察变量每次的变化。说实话,这方法虽然笨,但有时候真管用。
注意:如果程序已经跑完了,你再敲 continue,GDB 会告诉你「程序已退出」。这时候你得用 run 重新启动。
3.3 next —— 一步一步来
next,简写 n。它的特点是「不进入函数内部」。说白了,就是遇到函数调用时,直接跳过,把整个函数当成一行执行完。
(gdb) next
(gdb) n # 简写
举个例子:
int main() {
int a = 10;
int b = 20;
int c = add(a, b); // 如果在这里用 next,会直接得到结果,不进入 add 函数
printf("%d\n", c);
return 0;
}
当你停在 int c = add(a, b); 这一行时,敲 n,程序会直接执行完 add 函数,然后停在下一行 printf 那里。你想想看,如果你只是想看最终结果,不想关心 add 内部怎么算的,用 next 就对了。
3.4 step —— 钻进去看
step,简写 s。和 next 相反,它会「钻进」函数内部。
(gdb) step
(gdb) s # 简写
还是上面那个例子,如果你在 int c = add(a, b); 这一行敲 s,GDB 会跳进 add 函数的第一行代码。我曾经在调试一个内存泄漏问题时,就是靠 step 一步步跟进 malloc 的调用链,才发现有个指针没释放。
核心区别:
| 命令 | 行为 | 适用场景 |
|---|---|---|
| next (n) | 不进入函数 | 你信任这个函数,只想看外部逻辑 |
| step (s) | 进入函数 | 你想检查函数内部实现 |
3.5 print —— 看看变量值
print,简写 p。调试的核心就是看变量,没有 print 你啥也干不了。
(gdb) print var_name
(gdb) p var_name
(gdb) p/x var_name # 十六进制显示
(gdb) p/d var_name # 十进制显示
(gdb) p &var_name # 打印变量地址
我个人最常用的就是 p/x,因为嵌入式开发里经常要看寄存器值,十六进制更直观。有一次我调试一个串口驱动,数据老是发不对,用 p/x 一看,发现有个标志位被意外清零了——嗯,这种问题用眼睛看代码是看不出来的。
进阶用法:
p *ptr—— 打印指针指向的内容p array[0]@10—— 打印数组前10个元素p (struct foo *)0x1000—— 把某个地址强制转换成结构体指针并打印
3.6 list —— 看看源代码
list,简写 l。显示当前行附近的源代码。默认显示10行。
(gdb) list
(gdb) l # 简写
(gdb) l 20 # 显示第20行附近
(gdb) l main # 显示main函数附近的代码
(gdb) l func_name:30 # 显示func_name函数第30行附近
为什么需要 list?因为有时候你停在某个断点,光看行号根本想不起来这行是干嘛的。敲一下 l,上下文就出来了。我习惯在调试前先用 list 扫一遍代码,确认断点位置对不对。
注意:如果编译时加了 -g 选项但没有加 -O0,编译器可能会优化代码,导致 list 显示的行号和实际执行的不一致。我曾经被这个坑过,查了半天才发现是优化搞的鬼。
3.7 quit —— 退出调试
quit,简写 q。退出 GDB。
(gdb) quit
(gdb) q # 简写
如果你在调试过程中想退出,直接敲 q 就行。如果程序还在运行,GDB 会问你是否确认退出。这时候敲 y 就行。
避坑指南:我曾经在调试一个服务器程序时,忘了先停掉程序就直接 quit,结果后台进程还在跑,占着端口不放。后来我学乖了,退出前先用 kill 或者 detach 把程序处理干净。
知识体系总览
下面这张图把这七条命令的关系梳理了一下,你一看就明白:
这张图把调试流程串起来了:先用 run 启动,断点命中后,你可以用 list 看代码、用 print 看变量、用 next 或 step 单步执行。搞定了就 continue 继续跑,最后 quit 走人。说白了,调试就是这么回事。
我的建议:刚开始学的时候,别急着背命令。打开一个简单的 C 程序,设个断点,然后把这七条命令挨个试一遍。用不了十分钟,你就能记住。我当年就是这么干的,到现在肌肉记忆还在。
可可精品资料库