1. GDB入门:从零开始认识调试器
大家好,我是你们的老朋友。今天咱们聊聊GDB——这个我用了十几年、几乎每天都在用的调试工具。
说实话,刚入行那会儿,我总觉得调试就是printf大法。直到有一次,一个内存越界的bug让我整整熬了三个通宵...嗯,从那以后,我才真正开始认真学GDB。
1.1 GDB是什么?
GDB,全称GNU Debugger,是GNU项目下的一个调试器。说白了,它就是一个能让你「钻进程序内部」的工具。
你想想看,平时我们写代码,程序跑起来就像个黑盒子。你只知道输入和输出,中间发生了什么?不知道。GDB就是帮你打开这个黑盒子的钥匙。
核心能力:
- 让程序在任意位置暂停执行
- 查看变量、内存、寄存器的值
- 单步执行,逐行观察代码行为
- 修改程序状态,测试不同场景
1.2 GDB能解决什么问题?
我在项目中遇到过太多场景,没有GDB根本搞不定。这里列几个典型的:
| 问题类型 | 传统做法 | GDB做法 |
|---|---|---|
| 程序崩溃(段错误) | 加printf猜位置 | 直接定位到崩溃行,看调用栈 |
| 变量值不对 | 打印日志 | 断点停下,实时查看变量 |
| 死循环 | Ctrl+C重启 | 暂停后看当前执行位置 |
| 内存泄漏 | 靠经验猜 | 配合工具查看堆内存 |
| 逻辑分支走错 | 加条件打印 | 条件断点,精准命中 |
我曾经接手过一个项目,程序跑着跑着就崩,没有任何日志。团队里有人说「加printf试试」,我说「别,咱们用GDB」。结果第一次attach上去,不到10分钟就找到了问题——一个野指针在作怪。
1.3 GDB的安装与启动
安装GDB其实很简单。不同平台略有差异:
Linux(Ubuntu/Debian)
sudo apt-get install gdb
macOS
brew install gdb
# 或者用Xcode自带的lldb(GDB的变种)
Windows
我建议用MinGW或者WSL。Windows原生支持不太好,但也能用。
# MinGW环境下
pacman -S mingw-w64-x86_64-gdb
小提示:安装完后,在终端输入 gdb --version 检查是否成功。我习惯用 gdb -q 启动,这样不会显示版权信息,清爽很多。
1.4 GDB的基本工作流程
GDB的工作流程,说白了就三步:启动、设断点、调试。我画了一张图,帮你快速理解:
这张图展示了GDB的核心流程。我来详细说说每一步:
第一步:启动GDB
gdb ./myprogram
这会加载你的可执行文件。注意,编译时一定要加 -g 选项,否则GDB看不到源码和变量名。
警告:编译时忘记加 -g?那你看到的只有一堆汇编代码,根本没法调试。我曾经在客户现场犯过这个错,尴尬得不行。
第二步:设置断点
(gdb) break main
(gdb) break 42 # 在第42行设断点
(gdb) break func_name # 在函数入口设断点
断点就是让程序停下来的「路障」。你可以设多个,也可以设条件断点。
第三步:运行程序
(gdb) run
(gdb) run arg1 arg2 # 带参数运行
程序会在第一个断点处停下。这时候,你就可以开始「审讯」它了。
第四步:调试操作
这是最常用的几个命令:
next(或n):执行下一行,不进入函数内部step(或s):执行下一行,进入函数内部print var(或p var):查看变量值backtrace(或bt):查看调用栈continue(或c):继续运行到下一个断点
我的习惯:调试时我一般先用 next 快速过一遍,发现可疑的地方再用 step 钻进去看。别一上来就step,容易把自己绕晕。
第五步:退出
(gdb) quit
或者直接按 Ctrl+D。
1.5 一个完整的调试示例
光说不练假把式。咱们来看一个实际例子:
// test.c
#include <stdio.h>
int divide(int a, int b) {
return a / b; // 如果b=0,这里会崩溃
}
int main() {
int x = 10;
int y = 0;
int result = divide(x, y);
printf("result = %d\n", result);
return 0;
}
编译并调试:
$ gcc -g -o test test.c
$ gdb ./test
(gdb) break main
(gdb) run
(gdb) next # 执行到 int y = 0;
(gdb) print y # 查看y的值
$1 = 0
(gdb) next # 执行到 divide(x, y);
(gdb) step # 进入divide函数
(gdb) print b # 查看b的值
$2 = 0
(gdb) quit
看到了吗?在进入 divide 之前,我们就已经知道 b 是0了。这时候你可以选择修改 b 的值:
(gdb) set var b = 2
(gdb) continue
程序就能正常跑完了。这就是GDB的威力——你可以在运行时修改程序状态,测试各种场景。
核心要点回顾:
- GDB是调试利器,能解决段错误、变量异常、逻辑错误等问题
- 编译时加
-g选项是前提 - 工作流程:启动 → 设断点 → 运行 → 调试 → 退出
- 常用命令:break、run、next、step、print、continue、quit
好了,第一章就到这里。GDB入门其实不难,难的是养成用GDB的习惯。我见过太多工程师,明明装了GDB,遇到bug还是下意识地加printf。别这样,相信我,GDB用熟了,效率能翻倍。
可可精品资料库