2、GDB基础命令:run、continue、next、step、break、list、print、quit

调试器这东西,说白了就是给程序装了个「慢放镜头」。GDB 作为 Linux 下最经典的调试工具,我用了十几年,每次带新人时都会先让他们把这几个基础命令练熟。它们就像你工具箱里的螺丝刀和扳手——不一定每次都用得上,但用的时候必须顺手。

2.1 启动与退出:run 和 quit

先说说怎么让程序跑起来。你编译程序时记得加 -g 选项,不然 GDB 没法识别符号信息。我见过太多人忘了这步,然后跑来问我为什么看不到源码。

gcc -g -o myapp myapp.c
gdb ./myapp

进入 GDB 后,输入 run(或者简写 r)就能启动程序。如果程序需要命令行参数,直接跟在后面:

(gdb) run arg1 arg2

退出就简单了,quit(或 q)。嗯,这里要注意:如果你正在调试,GDB 会问你是否要退出,确认一下就行。

小技巧: 我个人习惯在 run 之前先设好断点,不然程序一下子就跑完了,你连看的机会都没有。

2.2 让程序停下来:break

break 是调试的核心。没有断点,调试就像在黑暗里找东西。你可以按函数名、行号、甚至条件来设断点。

(gdb) break main          // 在 main 函数入口
(gdb) break 42             // 在第 42 行
(gdb) break file.c:100     // 在 file.c 的第 100 行

我在项目中遇到过一种情况:一个 bug 只在循环第 5 次时出现。如果每次都手动按 continue 5 次,那效率太低了。这时候条件断点就派上用场:

(gdb) break 100 if i == 5

这样程序只在 i 等于 5 时停下来。省时省力。

避坑指南: 我曾经在条件断点里写错了变量名,结果断点根本没触发。排查了半天才发现是拼写错误。所以设完条件断点后,建议用 info break 检查一下。

2.3 单步执行:next 和 step

这两个命令经常让人混淆。简单来说:next(n)是「跳过函数调用」,step(s)是「进入函数内部」。

命令 作用 适用场景
next 执行下一行,不进入函数 你只关心当前函数逻辑
step 执行下一行,进入函数内部 你想看被调用函数的细节

举个例子:

int a = foo();   // 如果在这行用 next,直接得到结果
                  // 如果用 step,会跳进 foo 函数内部

你想想看,如果你在调试一个库函数,用 step 进去后可能看到一堆底层实现,反而更晕。所以我一般先用 next,确认问题不在当前函数时,再用 step 深入。

2.4 继续执行:continue

continue(c)让程序继续跑,直到遇到下一个断点或程序结束。这个命令看似简单,但配合条件断点用起来非常强大。

(gdb) continue

有时候你设了多个断点,想跳过当前这个,直接跑到下一个。这时候 continue 就是你的「快进键」。

核心要点: continue 不会重置程序状态,它只是从当前位置继续执行。如果你改了变量值,继续跑时会用新值。

2.5 查看源码和变量:list 和 print

list(l)用来查看源码上下文。默认显示当前行附近的 10 行代码。你可以指定行号或函数名:

(gdb) list          // 显示当前行附近
(gdb) list 50       // 显示第 50 行附近
(gdb) list main     // 显示 main 函数

print(p)则是查看变量值。这是调试时最常用的命令之一:

(gdb) print i
$1 = 5
(gdb) print &i
$2 = (int *) 0x7fffffffe4a0

你还可以用 print 查看表达式结果:

(gdb) print i * 2
$3 = 10

我曾经用 print 排查过一个诡异的数组越界问题。打印数组元素时发现某个值异常大,顺着索引往回查,才发现是循环条件写错了。

小技巧: print 的结果会保存在 $1、$2 这样的历史变量里。后面可以直接用 $1 引用,不用重新计算。

2.6 知识体系总览

下面这张图把本章的命令关系梳理了一下。你调试时基本就是在这几个命令之间切换:

GDB 调试流程 run (启动程序) break (设断点) continue (继续) next / step (单步) list (查看源码) print (查看变量) quit (退出) 调试流程:启动 → 设断点 → 单步/查看 → 继续 → 退出

2.7 实战组合拳

光记命令没用,得会用。我分享一个常用的调试套路:

  1. 启动程序:gdb ./app 然后 run
  2. 发现问题点:程序崩溃或输出不对,记下位置
  3. 设断点:在可疑位置 break 行号
  4. 重新运行:run,程序停在断点处
  5. 单步跟踪:用 next 或 step 一步步走
  6. 查看变量:print 变量名 确认值
  7. 继续或退出:没问题就 continue,调试完 quit

这个流程我用了十年,基本覆盖了 90% 的调试场景。剩下的 10% 需要更高级的技巧,比如条件断点、观察点等,后面章节会讲到。

避坑指南: 我曾经在调试多线程程序时,用 next 跳过了线程切换,结果漏掉了竞态条件。后来改用 step 配合线程断点才抓到问题。所以单线程用 next 没问题,多线程要小心。

好了,这 8 个命令就是 GDB 调试的基石。你先把它们练熟,后面学高级功能时才能得心应手。记住:调试不是猜谜,而是用工具一步步还原真相。