3、GDB基本命令:设置断点(break)、运行(run)、单步(step/next)、继续(continue)、打印(print)

好,咱们直接进入正题。调试器这东西,说白了就是让你能「看」着代码跑。GDB 的核心命令其实不多,但每一个都值得你好好琢磨。我个人习惯把这五个命令称为「调试五虎将」—— 断点、运行、单步、继续、打印。掌握了它们,你就掌握了 GDB 的命脉。

3.1 设置断点:让程序在你想停的地方停下来

断点是调试的起点。没有断点,程序就像脱缰的野马,你根本抓不住它。

最基本的用法是 break 行号。比如:

(gdb) break 42
Breakpoint 1 at 0x4005a0: file main.c, line 42.

这会在第 42 行设置一个断点。程序跑到这一行就会停下来,等你发号施令。

你也可以按函数名来设断点:

(gdb) break main
Breakpoint 2 at 0x400530: file main.c, line 12.

这会在 main 函数的入口处停下。我在项目中经常用这个,尤其是接手别人的代码时,先看看入口逻辑对不对。

小技巧: 如果你只想在某个条件成立时才停下,可以用条件断点。比如 break 42 if i == 5,这样只有 i 等于 5 时才会触发断点。省得你一次次手动跳过。

还有一种情况,你可能会遇到:断点设在了循环里,每次循环都停一次,烦不烦?嗯,这时候条件断点就派上用场了。

3.2 运行:让程序动起来

断点设好了,接下来就是让程序跑起来。命令很简单:run。

(gdb) run
Starting program: /home/user/myapp
Breakpoint 1, main () at main.c:12
12	    int x = 0;

程序会一直执行,直到遇到第一个断点。如果没有断点,它就会跑完全程。

你还可以给 run 传参数,就像在命令行里一样:

(gdb) run arg1 arg2 arg3

或者重定向输入输出:

(gdb) run < input.txt > output.txt

我记得有一次调试一个网络服务程序,需要模拟不同的输入场景。用 run < test_case.txt 这种方式,省了我不少事。

注意: 如果程序已经在运行中,再次输入 run 会询问你是否重新启动。输入 y 确认即可。我曾经不小心按了 n,结果程序卡在那不动了,还以为 GDB 坏了。

3.3 单步:一步一步看代码怎么走

单步执行是调试的精髓。GDB 提供了两个命令:step 和 next。

next 是「下一步」,它会执行当前行,然后停在下一行。如果当前行是一个函数调用,next 会直接执行完整个函数,不会进入函数内部。

(gdb) next
13	    int y = foo(x);  // 执行完这一行,直接到下一行

step 是「步入」,它会进入函数内部,一行一行地执行。

(gdb) step
foo (a=0) at foo.c:5
5	    return a + 1;

你想想看,什么时候用 next,什么时候用 step?

我的经验是:如果你怀疑某个函数内部有问题,就用 step 进去看看。如果你只是想跳过这个函数,用 next 就对了。说白了,step 是「深挖」,next 是「跳过」。

避坑指南: 我曾经在调试一个大型项目时,不小心用 step 进入了一个标准库函数,结果在里面绕了半天出不来。后来学乖了,不确定的函数先用 next 跳过,真有需要再 step。

3.4 继续:让程序飞一会儿

单步执行虽然精细,但有时候你只想让程序跑到下一个断点。这时候就用 continue(简写 c)。

(gdb) continue
Continuing.
Breakpoint 2, main () at main.c:20
20	    printf("x = %d\n", x);

程序会继续执行,直到遇到下一个断点或者程序结束。

你还可以指定跳过多少个断点:

(gdb) continue 3

这会跳过接下来的 3 个断点,在第 4 个断点处停下。嗯,这个用法我很少用,但在某些循环调试场景下确实能省点事。

3.5 打印:看看变量到底值多少钱

调试的核心就是看变量值。GDB 的 print 命令(简写 p)就是干这个的。

(gdb) print x
$1 = 42

你可以打印任何表达式:

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

甚至打印结构体:

(gdb) print my_struct
$4 = {name = "hello", value = 10, next = 0x0}

如果结构体很大,可以用 print /x 以十六进制显示,或者 print /t 以二进制显示。

小技巧: 用 display 命令可以让 GDB 每次停下来时自动打印某个变量。比如 display x,这样你就不用每次都手动输入 print x 了。我在调试循环时特别喜欢用这个。

3.6 知识体系总览

下面这张图总结了这五个命令的关系和用法。你可以把它当作一个快速参考。

GDB 调试五虎将 · 知识体系 GDB 调试流程 break 设置断点,让程序暂停 run 启动程序,跑到断点 step / next 单步执行,步入或跳过 continue 继续执行到下一个断点 print 打印变量值,查看状态 循环调试 提示:这五个命令构成了 GDB 调试的核心循环,熟练掌握它们就能应对大部分调试场景

3.7 实战组合拳

光知道单个命令还不够,你得学会把它们组合起来用。我举个例子:

(gdb) break main          # 在 main 函数入口设断点
(gdb) run                  # 启动程序,停在 main 入口
(gdb) next                 # 跳过初始化代码
(gdb) step                 # 进入可疑函数
(gdb) print buffer         # 看看 buffer 内容
(gdb) continue             # 继续跑,到下一个断点
(gdb) print result         # 看看最终结果

这套组合拳我用了十年,几乎每天都会用到。你想想看,是不是很顺手?

核心要点:
  • break 设断点,run 启动,step/next 单步,continue 继续,print 看值
  • 条件断点用 break 行号 if 条件
  • step 进函数,next 跳过函数
  • display 可以自动打印变量,省得每次手动输入

好了,这五个命令就讲到这里。记住,调试不是一蹴而就的事,多练练自然就熟了。下次遇到 bug,别急着改代码,先想想能不能用 GDB 把它揪出来。

可可精品资料库