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
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时才触发
我曾经在一个网络协议栈的调试中,用条件断点抓一个只在特定报文长度下才触发的内存越界。设了个 break 256 if pkt_len == 1500,一次命中。嗯,这就是经验。
3.4 执行控制:continue、next、step
这三个命令控制程序怎么「走」。我画了张图帮你理解它们的关系:
continue:让程序继续跑,直到遇到下一个断点或程序结束。说白了就是「接着来」。
(gdb) continue
(gdb) c # 简写形式
next:单步执行,遇到函数调用会跳过,不进入函数内部。这个我用的最多,因为大部分时候你只关心当前函数的逻辑。
(gdb) next
(gdb) n # 简写
step:也是单步执行,但遇到函数调用会进入函数内部。你想看某个函数怎么实现的,就用 step。
(gdb) step
(gdb) s # 简写
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 进程还挂在后台。虽然影响不大,但总归不优雅。