GDB(GNU Debugger)是 GNU 项目开发的一款强大且通用的命令行调试器,主要用于调试 C、C++、Go、Rust、Ada 等多种编程语言编写的程序。它是 Linux 和类 Unix 系统下最常用、最核心的调试工具
简单来说,GDB 能让你像“侦探”一样深入程序内部,观察、控制和分析它的运行状态,从而高效地定位和修复 Bug(尤其是崩溃和逻辑错误)。

🧠 GDB 的核心功能

GDB 的能力主要围绕以下四个方面展开:

功能 说明 常用命令/操作
🚀 启动与控制程序 按你的要求运行程序,随时暂停、继续、或单步执行。 run ®, continue ©, next (n), step (s), finish
🔴 设置断点 在代码的指定行、函数入口或条件表达式处暂停程序。 break (b), break <行号>, break <函数名>, break <行号> if <条件>
🔍 检查程序状态 当程序暂停时,查看变量、内存、寄存器、调用栈等内部状态。 print §, backtrace (bt), info locals, info args, x
🛠️ 动态修改环境 在调试过程中修改变量值、调用函数,甚至改变执行顺序,测试不同修复方案。 set var <变量>=<值>, call <函数()>, jump <地址>

📦 如何使用 GDB 调试程序

使用 GDB 调试程序通常需要遵循以下步骤,其核心流程可概括如下:

编译程序
加入-g选项

启动GDB
gdb ./程序名

设置断点
break 行号/函数名

运行程序
run

程序是否在断点处暂停?

检查程序状态
print变量/backtrace调用栈

单步执行或继续
next/step/continue

是否发现Bug?

修复代码

继续调试至结束

程序运行结束
或崩溃

分析崩溃信息
或正常退出

1. 编译程序时加入调试信息

这是使用 GDB 的前提。必须使用 gccg++ 编译时加上 -g 选项,才能生成包含调试符号(变量名、行号等)的可执行文件。

# 示例:编译 test.cpp 生成带调试信息的可执行程序 test
g++ -g test.cpp -o test
2. 启动 GDB 并加载程序

在终端中输入 gdb 加上你的可执行程序路径即可启动。

gdb ./test

也可以直接在 GDB 中使用 file 命令加载程序:

(gdb) file ./test
3. 设置断点

使用 break 命令(简写为 b)设置断点,程序运行到此处会暂停。

(gdb) break main        # 在 main 函数入口处设置断点
(gdb) b 15              # 在第 15 行设置断点
(gdb) b my_function     # 在 my_function 函数入口设置断点
4. 运行程序

使用 run 命令(简写为 r)启动程序。程序会一直运行直到遇到断点。

(gdb) run

如果程序需要参数,可以在 run 后面直接跟上参数:

(gdb) run arg1 arg2
5. 检查程序状态

程序暂停后,你可以使用各种命令检查其状态:

  • 查看变量值print (简写为 p)
    (gdb) print sum
    $1 = 10
    (gdb) p *array@10     # 查看数组array前10个元素
    
  • 查看调用栈backtrace (简写为 bt),了解函数调用关系
    (gdb) backtrace
    #0  main () at test.cpp:15
    
  • 查看局部变量info locals
  • 查看内存内容x 命令
6. 控制程序执行
  • 单步执行(不进入函数)next (简写为 n)
  • 单步执行(进入函数)step (简写为 s)
  • 继续运行到下一个断点continue (简写为 c)
  • 执行完当前函数finish
7. 修改变量并测试

可以在调试过程中修改变量的值,以测试不同的执行路径或修复方案。

(gdb) set var i = 5      # 将变量 i 的值修改为 5

🐛 使用 GDB 分析程序崩溃(如段错误)

当程序崩溃(如出现 Segmentation fault)时,GDB 是事后分析的利器。

  1. 直接调试崩溃程序:用 GDB 运行程序,当其崩溃时,GDB 会自动捕获并暂停。此时使用 bt 命令查看崩溃时的调用栈,能立即定位到出问题的函数和行号。
    (gdb) run
    Program received signal SIGSEGV, Segmentation fault.
    0x0000555555555170 in main () at test.cpp:15
    15	        *p = 100;      // 崩溃在这一行
    (gdb) bt
    #0  0x0000555555555170 in main () at test.cpp:15
    
  2. 分析 Core Dump 文件:如果系统生成了 core dump 文件(通常在崩溃时自动生成),可以用 GDB 加载它来复盘崩溃现场。
    gdb ./test core       # 加载可执行程序和 core 文件
    (gdb) bt              # 查看崩溃时的调用栈
    

💡 GDB 使用技巧与进阶

  • 查看源代码list (简写为 l) 命令可以查看源代码。
    (gdb) list           # 查看当前位置附近的代码
    (gdb) list 15        # 查看第15行附近的代码
    (gdb) list main      # 查看 main 函数的代码
    
  • 观察点(Watchpoint)watch 命令可以设置观察点,当某个表达式的值发生变化时程序暂停,非常适合追踪变量被意外修改的情况。
  • 条件断点:设置断点时可以附加条件,只有条件满足才暂停,极大提高调试效率。
    (gdb) break 10 if i == 5    # 当 i 等于 5 时,在第10行暂停
    
  • 使用 .gdbinit 文件:可以在用户主目录下创建 .gdbinit 文件,写入常用的 GDB 命令,GDB 启动时会自动执行,避免重复输入。
  • 图形化前端:如果觉得纯命令行不便,可以使用基于 GDB 的图形化或文本前端工具,如 cgdb(分屏显示源码和命令)、DDD 等。

⚠️ 注意事项

  1. 务必使用 -g 编译:忘记加 -g 选项会导致 GDB 无法显示源代码行号和变量名,几乎无法调试。
  2. 优化与调试信息:在编译时使用 -O 优化选项(如 -O2)可能会打乱代码顺序,使调试变得困难。调试时建议关闭优化或使用 -Og(优化调试体验)。
  3. GDB 与 IDE 调试器:VS Code、CLion 等 IDE 的调试功能底层通常也是调用 GDB 或 LLDB,它们提供了更友好的图形界面。

📚 总结与学习资源

GDB 是 Linux 环境下 C/C++ 开发者必备的核心技能。它虽然基于命令行,但功能强大,灵活性远超许多图形化调试器。

💡 学习建议:从最基础的 runbreaknextprintbacktrace 命令练起,结合实际调试一个小程序,很快就能上手。遇到具体问题再查阅手册学习新命令。

  • 官方手册info gdb 或在线手册 GDB Documentation 是最权威的参考。
  • 实践练习:多写几个有 Bug 的小程序(如数组越界、空指针解引用、死循环),用 GDB 去定位和修复它们,这是最快的掌握方式。
  • 推荐教程
    • 《GDB Pocket Reference》
    • 许多优秀的 Linux C/C++ 开发书籍都有专门的 GDB 章节。
      掌握 GDB,你就能从“程序能跑通”进化到“程序为什么能跑通/跑崩”,真正理解程序的内部世界。

更多推荐