3、GDB基本命令:run、continue、next、step、break、list、print、quit

好,咱们直接进入正题。调试器这东西,说白了就是让你能「看」着代码跑。GDB 这八个命令,我用了十几年,可以说覆盖了日常调试 90% 的场景。你把这几个玩熟了,基本就能横着走了。

3.1 启动与退出:run 和 quit

run 就是让程序跑起来。你想想看,你写了个程序,编译完扔进 GDB,不 run 一下它怎么动?

(gdb) run
(gdb) run arg1 arg2   # 带参数启动
(gdb) run < input.txt # 重定向输入

我个人习惯在 run 之前先打个断点,不然程序一溜烟跑完,你啥也看不到。嗯,这里要注意:如果你修改了代码重新编译,不用退出 GDB,直接再敲一次 run 就行,它会自动加载新的可执行文件。

quit 就更简单了,退出 GDB。我见过新手直接关终端窗口的,其实敲个 q 回车就行。

(gdb) quit
小技巧: 如果你不小心进了 GDB 想退出,Ctrl+D 也可以,效果等同于 quit。

3.2 代码浏览:list

list 命令用来查看源代码。默认显示当前执行位置附近的代码,每次显示 10 行。

(gdb) list          # 显示当前行附近代码
(gdb) list 20       # 显示第20行附近
(gdb) list main     # 显示main函数附近
(gdb) list 30,40    # 显示30到40行

我记得刚学 GDB 时,总记不住 list 的用法。后来发现一个规律:你连续敲 list,它会一页一页往下翻,就像看纸质书一样。这个设计其实挺人性化的。

3.3 断点管理:break

break 是调试的核心。没有断点,调试就像在黑暗里摸象。

(gdb) break main          # 在main函数入口打断点
(gdb) break 42            # 在第42行打断点
(gdb) break file.c:100    # 在file.c的100行打断点
(gdb) break func if x==0  # 条件断点,x等于0时才触发
重点: 条件断点非常实用。我在项目中遇到过循环跑 10 万次,只在第 99999 次才出 bug。你要是不加条件,手都按酸了也等不到那一刻。

我曾经在一个网络协议栈的调试中,用条件断点抓一个只在特定报文长度下才触发的内存越界。设了个 break 256 if pkt_len == 1500,一次命中。嗯,这就是经验。

3.4 执行控制:continue、next、step

这三个命令控制程序怎么「走」。我画了张图帮你理解它们的关系:

GDB 执行控制流程 程序暂停 continue 跑到下一个断点 next 单步跳过函数 step 单步进入函数 继续执行 直到下一个断点 执行下一行 不进入函数内部 进入函数 停在函数第一行 三者区别:continue 跑大段代码,next 跳过函数,step 钻进函数

continue:让程序继续跑,直到遇到下一个断点或程序结束。说白了就是「接着来」。

(gdb) continue
(gdb) c  # 简写形式

next:单步执行,遇到函数调用会跳过,不进入函数内部。这个我用的最多,因为大部分时候你只关心当前函数的逻辑。

(gdb) next
(gdb) n  # 简写

step:也是单步执行,但遇到函数调用会进入函数内部。你想看某个函数怎么实现的,就用 step。

(gdb) step
(gdb) s  # 简写
避坑指南: 我曾经在调试一个大型项目时,不小心在 printf 上用了 step,结果一头扎进了 glibc 的源码里,几百行汇编看得我头皮发麻。记住:标准库函数别用 step,用 next 跳过。

3.5 变量查看:print

print 用来查看变量的值。这是调试中最频繁的操作,没有之一。

(gdb) print x
(gdb) print &x        # 查看变量地址
(gdb) print *ptr      # 查看指针指向的值
(gdb) print arr[5]    # 查看数组元素
(gdb) print /x val    # 以十六进制显示
(gdb) print /f val    # 以浮点数显示

格式控制符很实用。我排查内存问题时,经常用 print /x 看十六进制,一眼就能看出字节对齐有没有问题。

格式符 含义 示例
/x 十六进制 print /x val
/d 有符号十进制 print /d val
/u 无符号十进制 print /u val
/f 浮点数 print /f val
/c 字符 print /c val
/s 字符串 print /s str
实用技巧: 用 display 命令可以让变量自动显示,每次程序暂停时都会打印出来。比如 display x,省得你每次都敲 print。

3.6 实战组合拳

光说理论没意思,我给你一个真实场景。假设你在调试一个链表操作,怀疑某个节点被意外释放了:

# 1. 在操作函数入口打断点
(gdb) break list_operation

# 2. 运行程序
(gdb) run

# 3. 查看当前节点指针
(gdb) print node
(gdb) print node->next

# 4. 单步执行,观察每一步的变化
(gdb) next
(gdb) print node->data

# 5. 如果怀疑 free 有问题,在 free 处打断点
(gdb) break free if ptr == node

# 6. 继续执行
(gdb) continue

这套组合拳我用了无数次。说白了,调试就是「设断点 → 看变量 → 单步走 → 再设断点」的循环。你熟练了,bug 自然就藏不住了。

最后说一句,quit 别忘了。我见过有人调试完了直接关终端,GDB 进程还挂在后台。虽然影响不大,但总归不优雅。

可可精品资料库