2. GDB基本命令:run、break、next、step、continue、print、quit、list命令详解
调试C/C++程序,说白了就是跟代码的「灵魂」对话。而GDB,就是那个翻译官。我刚开始用GDB时,其实就靠七八个命令活下来的。今天咱们就把这几个核心命令掰开揉碎,讲透它。
核心思想:GDB调试的本质是「控制执行流 + 观察状态」。run负责启动,break设断点,next/step控制步进,continue恢复运行,print看变量,list读源码,quit收工。就这么简单。
2.1 run —— 让程序跑起来
run(简写r)是启动程序的命令。你想想看,没有它,后面所有命令都是空谈。
(gdb) run
(gdb) r # 简写形式
(gdb) run arg1 arg2 # 带命令行参数启动
(gdb) run < input.txt # 重定向输入
我在项目中遇到过一个问题:程序启动时需要加载一个几百MB的配置文件。每次run都要等半天。后来我发现,可以用set args提前设置参数,然后直接run就行。
小技巧:如果程序已经跑过一次,再次run时GDB会问你是否重启。用y确认就行。我个人习惯直接敲r,省事。
2.2 break —— 让程序停下来
break(简写b)是断点命令。没有断点,程序就像脱缰的野马,你根本抓不住它。
(gdb) break main # 在main函数入口设断点
(gdb) b 42 # 在当前文件第42行设断点
(gdb) b foo.c:100 # 在foo.c第100行设断点
(gdb) b my_function # 在函数my_function入口设断点
(gdb) b *0x400520 # 在内存地址0x400520设断点
嗯,这里要注意:断点可以设多个,GDB会给每个断点分配一个编号。你可以用info breakpoints查看所有断点。
避坑指南:我曾经在循环体里设了断点,结果每次循环都停一次,调试到崩溃。后来学会了用condition给断点加条件,比如condition 1 i == 100,只在i等于100时才停。这招太实用了。
2.3 next —— 一步一步走
next(简写n)是「单步跳过」命令。它会执行当前行,如果遇到函数调用,不会进入函数内部,直接执行完整个函数。
(gdb) next
(gdb) n # 简写形式
(gdb) next 5 # 连续执行5步
为什么会这样?因为next把函数调用当作一个「黑盒」来处理。你只关心结果,不关心内部实现时,用next最合适。
2.4 step —— 钻进函数里看看
step(简写s)是「单步进入」命令。它和next的区别在于:遇到函数调用时,step会进入函数内部,一行一行地执行。
(gdb) step
(gdb) s # 简写形式
(gdb) step 3 # 连续执行3步
我个人习惯是:调试自己写的函数用step,调试库函数用next。你想想看,要是printf这种函数你也step进去,那得看到猴年马月去。
| 命令 | 行为 | 适用场景 |
|---|---|---|
| next (n) | 不进入函数,直接执行完 | 函数逻辑已确认,只看结果 |
| step (s) | 进入函数内部,逐行执行 | 需要排查函数内部逻辑 |
2.5 continue —— 继续跑起来
continue(简写c)让程序从当前断点处继续执行,直到遇到下一个断点或程序结束。
(gdb) continue
(gdb) c # 简写形式
(gdb) c 5 # 忽略当前断点5次,第6次才停
我记得有一次调试一个死循环,设了断点后一直c,手都按酸了。后来发现c 5可以跳过前5次命中,直接停在第6次。嗯,这功能藏得有点深,但真香。
2.6 print —— 看看变量值
print(简写p)是观察变量的命令。调试的核心就是「看变量」,没有print,你就是在盲调。
(gdb) print i # 打印变量i的值
(gdb) p &i # 打印变量i的地址
(gdb) p *ptr # 打印指针指向的值
(gdb) p array[5] # 打印数组第6个元素
(gdb) p/x 0x100 # 以十六进制打印
(gdb) p/d 0x100 # 以十进制打印
(gdb) p/f 3.14 # 以浮点数打印
小技巧:GDB支持表达式计算。比如p i + j * 2,它会先计算再打印。我在项目中经常用p sizeof(struct xxx)来确认结构体大小,比翻头文件快多了。
2.7 quit —— 退出调试
quit(简写q)退出GDB。没什么好说的,但有个小细节:如果程序还在运行,GDB会问你是否要终止。用y确认就行。
(gdb) quit
(gdb) q # 简写形式
2.8 list —— 看看源码
list(简写l)显示源代码。调试时经常需要确认当前执行到哪一行了,或者看看上下文。
(gdb) list # 显示当前行附近的10行
(gdb) l 42 # 显示第42行附近的10行
(gdb) l main # 显示main函数附近的代码
(gdb) l foo.c:100 # 显示foo.c第100行附近的代码
(gdb) l 1,50 # 显示第1行到第50行
我个人习惯是:每次step或next之后,先l一下看看上下文,确认自己没跑偏。你想想看,要是跑到了完全没想到的代码分支里,那调试就变成猜谜了。
核心总结:这8个命令构成了GDB调试的「最小可用集」。run启动,break设停,next/step控制步进,continue恢复,print观察,list确认位置,quit收工。把这几个练熟了,90%的调试场景你都能应付。
实战建议:把这8个命令记在脑子里,调试时手不要停。我刚开始学GDB时,把命令写在便签纸上贴在显示器边上,用了一周就烂熟于心了。你试试看,真的不难。