一、GDB 基础认知
1. 什么是 GDB?
GDB 是 GNU 开源的命令行调试器,主要用于调试C/C++、Go、Assembly 等编译型语言的程序,核心作用是:
- 定位程序崩溃(如段错误、空指针)的原因;
- 跟踪程序执行流程,查看变量 / 内存 / 寄存器的值;
- 控制程序分步执行(单步、断点),验证逻辑是否符合预期;
- 调试多进程、多线程程序(进阶场景)。
2. 前置条件(新手必看)
调试前必须在编译程序时添加 -g 参数(保留调试信息),否则 GDB 无法识别代码行、变量名等:
bash
运行
# 编译示例:test.c → 可执行文件test(带调试信息)
gcc -g test.c -o test
注:如果用 make 编译,需确保 Makefile 中 CFLAGS 包含 -g(如 CFLAGS = -g -Wall)。
二、GDB 基本使用流程(核心)
以调试上述 test 程序为例,完整流程分为 5 步:
| 1. 启动 GDB | gdb ./test | 启动 GDB 并加载可执行文件 test,进入 GDB 交互界面(提示符为 (gdb)) |
| 2. 设置断点 | break 行号 / break 函数名 | 在指定位置暂停程序执行(断点是调试的核心) |
| 3. 运行程序 | run(简写 r) | 启动程序,程序会执行到第一个断点处暂停 |
| 4. 调试操作 | 单步执行、查看变量、查看内存等 | 核心调试环节,验证程序逻辑 |
| 5. 退出 GDB | quit(简写 q) | 退出调试界面,回到终端 |
三、GDB 常用核心命令(新手高频)
1. 断点相关命令(最常用)
| break 行号 | b 行号 | 在指定行设置断点 | b 10(在第 10 行设断点) |
| break 函数名 | b 函数名 | 在函数入口设断点 | b main(在 main 函数开头设断点) |
| break 文件名:行号 | b 文件名:行号 | 多文件调试时指定文件的行 | b utils.c:25 |
| info breakpoints | info b | 查看所有断点信息(编号、位置、状态) | – |
| delete 断点编号 | d 编号 | 删除指定断点 | d 1(删除编号为 1 的断点) |
| disable 断点编号 | disable 编号 | 禁用断点(保留但不生效) | disable 1 |
| enable 断点编号 | enable 编号 | 启用禁用的断点 | enable 1 |
2. 执行控制命令(分步调试)
| run | r | 启动 / 重启程序 | 程序会执行到第一个断点暂停;可传参数:r arg1 arg2 |
| next | n | 单步执行(跳过函数调用) | 执行一行代码,若该行是函数调用(如 func()),直接执行完整个函数 |
| step | s | 单步执行(进入函数调用) | 执行一行代码,若该行是函数调用,进入函数内部执行 |
| continue | c | 继续执行程序 | 从当前断点处继续运行,直到下一个断点或程序结束 |
| finish | fin | 执行完当前函数,返回到调用处 | 适合进入函数后想快速退出的场景 |
3. 查看数据命令(验证变量 / 内存)
| print 变量名 | p 变量名 | 打印变量的值 | p num(打印 num 的值)、p arr[0](打印数组第一个元素) |
| print 表达式 | p 表达式 | 打印表达式结果 | p a + b、p ptr->val(打印指针指向的结构体成员) |
| display 变量名 | disp 变量名 | 自动显示变量值(每次执行后都打印) | disp count(跟踪 count 的变化) |
| undisplay 编号 | undisp 编号 | 取消自动显示 | undisp 1 |
| x/格式 内存地址 | – | 查看内存内容(x=examine) | x/10xw 0x7fffffffe480(以 16 进制、4 字节为单位,查看从该地址开始的 10 个值) |
内存格式说明:x=16 进制、d= 十进制、s= 字符串、w=4 字节、b=1 字节;如 x/5sb 0x地址 表示查看 5 个字节的字符串。
4. 其他实用命令
| backtrace | bt | 查看调用栈(定位崩溃位置的核心) | 程序崩溃时,bt 能显示崩溃时的函数调用链(哪行、哪个函数、谁调用的) |
| frame 栈帧编号 | f 编号 | 切换到指定栈帧(查看对应函数的变量) | f 0(切换到崩溃的函数栈帧) |
| set var 变量=值 | – | 修改变量的值(调试时临时测试) | set var num=10(把 num 的值改为 10) |
| list | l | 查看当前行附近的代码 | l(显示当前断点周围 10 行)、l 10,20(显示 10-20 行) |
四、实战示例(新手必练)
1. 准备测试代码(test.c)
c
运行
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int x = 5, y = 3;
int sum = add(x, y);
printf("sum = %d\\n", sum);
return 0;
}
2. 调试步骤
bash
运行
# 1. 编译(加-g)
gcc -g test.c -o test
# 2. 启动GDB
gdb ./test
# 3. 设置断点(main函数和add函数)
(gdb) b main
(gdb) b add
# 4. 运行程序
(gdb) r
# 程序暂停在main函数开头,提示:Breakpoint 1, main () at test.c:8
# 第8行是:int x = 5, y = 3;
# 5. 单步执行(next)
(gdb) n
# 执行完第8行,到第9行:int sum = add(x, y);
# 6. 进入add函数(step)
(gdb) s
# 进入add函数,暂停在第4行:return a + b;
# 7. 查看变量a和b的值
(gdb) p a
$1 = 5
(gdb) p b
$2 = 3
# 8. 执行完add函数(finish)
(gdb) fin
# 返回到main函数第9行,提示:sum = 8
# 9. 继续执行程序(continue)
(gdb) c
# 程序执行完,打印sum = 8,正常退出
# 10. 退出GDB
(gdb) q