4. GDB基本命令:run、continue、next、step、list、print、quit

调试器这东西,说白了就是让你能「看」着程序跑。GDB 最核心的几条命令,我用了十几年,每天还在用。今天咱们就把它们捋清楚。

4.1 启动与运行:run 和 quit

run 是启动程序的命令。在 GDB 里加载完可执行文件后,敲 run 就开始跑了。我个人习惯在 run 后面直接带参数,比如:

(gdb) run arg1 arg2 < input.txt

这等价于在 shell 里执行 ./a.out arg1 arg2 < input.txt。嗯,这里有个小坑——如果你忘了加参数,程序跑起来发现不对劲,还得 quit 退出去重来。

quit 就是退出 GDB。没什么好说的,但注意:如果你正在调试一个卡住的程序,直接 quit 可能会让进程变成僵尸。我建议先 kill 掉再退。

小技巧: 用 run 启动后,程序崩溃了,GDB 会自动停在崩溃点。这时候别急着 quit,先看看堆栈。

4.2 断点后的控制:continue、next、step

这三个命令是调试的核心。它们决定了程序怎么「走」。

continue(简写 c):让程序继续跑,直到遇到下一个断点或结束。我在项目中遇到过一种情况:一个死循环里打了断点,每次 continue 都停在同一行。后来发现是循环条件写错了——continue 只是「放行」,不是「跳过」。

next(简写 n):单步执行,但遇到函数调用会「跨过去」。说白了,它把整个函数调用当成一步。举个例子:

int main() {
    int a = foo();  // 断点停在这里
    int b = bar();
    return 0;
}

如果你用 next,GDB 会直接执行完 foo() 并停在下一行。你不需要关心 foo 内部发生了什么。

step(简写 s):单步执行,但遇到函数调用会「钻进去」。还是上面那个例子,用 step 就会进入 foo() 函数内部。我曾经用 step 追过一个诡异的段错误,发现是某个库函数里传了个空指针——要是用 next 就漏掉了。

注意: step 进入系统库函数时,可能会看到一堆汇编代码。这时候别慌,用 finish 可以跳出当前函数。

4.3 查看代码与变量:list 和 print

list(简写 l):显示源代码。默认显示当前行附近的 10 行。你可以指定行号或函数名:

(gdb) list 42        // 显示第42行附近
(gdb) list main      // 显示main函数
(gdb) list foo.c:10  // 显示foo.c的第10行

我个人习惯用 list 快速定位上下文。调试时看到断点停在哪,敲个 list 就能看到周围代码,比切回编辑器快多了。

print(简写 p):打印变量或表达式的值。这是最常用的命令,没有之一。基本用法:

(gdb) print x
$1 = 42
(gdb) print &x
$2 = (int *) 0x7fffffffe4a0
(gdb) print x + y
$3 = 100

你想想看,print 还能打印结构体、数组、指针。我调试网络程序时经常用 print *p 看指针指向的内容。有一次发现一个链表节点指向了野地址,就是靠 print 一步步查出来的。

核心要点: print 后面可以跟任何合法的 C/C++ 表达式,包括函数调用。但注意——调用函数可能会改变程序状态,慎用。

4.4 命令速查表

命令 简写 作用 常用场景
run r 启动程序 开始调试
continue c 继续执行 断点后放行
next n 单步跳过函数 不关心函数内部
step s 单步进入函数 追踪函数内部逻辑
list l 显示源代码 查看上下文
print p 打印变量/表达式 检查变量值
quit q 退出 GDB 结束调试

4.5 知识体系图

下面这张图展示了本章命令之间的逻辑关系:

GDB 基本命令 运行控制 run continue quit 单步调试 next step 查看信息 list print 核心逻辑:启动 → 断点 → 单步/继续 → 查看变量 → 退出 next 跳过函数,step 进入函数,continue 跑到下一断点

4.6 避坑指南

  • 我曾经用 next 调试一个多线程程序,结果发现 next 只影响当前线程,其他线程还在跑。嗯,多线程调试得用 thread apply all 配合。
  • 我曾经在 print 一个超大数组时,GDB 卡了十几秒。后来才知道可以用 print *array@10 只打印前 10 个元素。
  • 注意: list 显示的是源代码,如果编译时没加 -g 选项,你只能看到汇编。所以编译时一定要加 -g。
我的习惯: 调试时先 list 看上下文,然后 print 关键变量,再用 next 或 step 一步步走。遇到可疑的函数调用,果断 step 进去看看。

说白了,这七个命令就是 GDB 的「七种武器」。run 和 quit 管开始结束,continue、next、step 管流程控制,list 和 print 管信息查看。掌握了它们,你已经能解决 80% 的调试问题了。

可可精品资料库