1. GDB入门
说实话,我接触GDB已经十几年了。刚入行那会儿,调试C程序全靠printf大法,代码里到处是printf("here: %d\n", x)这种语句。直到有一次,一个内存越界的bug让我排查了整整三天,最后是前辈用GDB十分钟就定位到了问题。嗯,从那天起,我就老老实实学GDB了。
GDB是什么?全称是GNU Debugger,说白了就是一个让你能「钻进程序内部」看个究竟的工具。它不是帮你写代码的,而是帮你搞清楚「代码到底在干什么」的。
GDB能做什么?
我把它能做的事情归纳成四类,你想想看,是不是正好对应了调试的四个核心需求:
- 让程序停下来 —— 在指定行、指定函数、指定条件处暂停执行
- 查看程序状态 —— 变量值、寄存器、内存、堆栈,想看什么看什么
- 改变程序行为 —— 修改变量值、跳过某行代码、强制返回
- 追踪程序轨迹 —— 谁调用了谁、参数是什么、返回值是什么
我个人习惯把GDB比作「程序的CT机」。printf就像X光片,只能看到静态的、你预设好的画面。而GDB是动态的,你可以一层层切进去,看到程序运行的每一个细节。
核心观点: GDB不是万能的,但没有GDB是万万不能的。尤其是做系统编程、嵌入式开发、或者排查内存问题的时候,GDB几乎是必备技能。
GDB的安装
安装GDB其实很简单。不同平台略有差异,我列个表给你参考:
| 操作系统 | 安装命令 | 备注 |
|---|---|---|
| Ubuntu/Debian | sudo apt-get install gdb |
一般系统自带,版本可能较旧 |
| CentOS/RHEL | sudo yum install gdb |
或者用dnf |
| macOS | brew install gdb |
需要签名,稍麻烦 |
| Windows | 安装MinGW或WSL | 推荐WSL + Ubuntu |
安装完成后,在终端输入gdb --version,能看到版本号就说明装好了。我个人建议用10.0以上的版本,新版本对C++17、Python扩展支持更好。
小技巧: 如果你在macOS上遇到gdb无法调试的问题,大概率是签名没做。我曾经在这上面折腾了两个小时,后来发现用lldb其实也行——但咱们课程还是以GDB为主。
基本使用流程
GDB的基本使用流程,我总结为四步走:
- 编译时加-g选项 —— 这是前提,不加-g就没有调试信息
- 启动GDB —— 用gdb命令加载你的程序
- 设置断点 —— 告诉GDB在哪里停下来
- 运行并调试 —— 用run、next、step、print等命令
来看一个最简单的例子。假设我们有这样一个程序:
// test.c
#include <stdio.h>
int add(int a, int b) {
int result = a + b;
return result;
}
int main() {
int x = 10;
int y = 20;
int sum = add(x, y);
printf("sum = %d\n", sum);
return 0;
}
编译和调试的完整流程:
# 第一步:编译,必须加-g
gcc -g -o test test.c
# 第二步:启动GDB
gdb ./test
# 第三步:设置断点
(gdb) break main
(gdb) break add
# 第四步:运行
(gdb) run
# 程序会在main函数入口停下来
# 然后你可以:
(gdb) next # 单步执行,不进入函数
(gdb) step # 单步执行,进入函数
(gdb) print x # 查看变量x的值
(gdb) continue # 继续运行到下一个断点
(gdb) quit # 退出GDB
注意: 很多新手会忘记加-g选项,然后发现GDB里看不到源码、看不到变量名。嗯,我刚开始也犯过这个错。记住:-g是调试信息的开关,不加它GDB就是个瞎子。
GDB的核心知识体系
为了让你对GDB有个整体认识,我画了一张图。这张图展示了GDB调试的核心逻辑:
这张图其实就概括了GDB能做的所有事情。你不需要一下子记住所有命令,先记住这四个方向就行。后面的章节,我们会一个一个深入进去。
我的建议: 刚开始学GDB,别急着背命令。先拿一个简单的程序,把run、break、next、step、print这五个命令玩熟。剩下的命令,遇到具体问题再查。我就是这么过来的。
好了,这一章就到这里。GDB的安装和基本流程你已经了解了。下一章我们会深入第一个核心能力——如何让程序在你想停的地方停下来。
可可精品资料库