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 调试程序通常需要遵循以下步骤,其核心流程可概括如下:
#mermaid-svg-dW2o2g1vSQTupjNb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dW2o2g1vSQTupjNb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dW2o2g1vSQTupjNb .error-icon{fill:#552222;}#mermaid-svg-dW2o2g1vSQTupjNb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dW2o2g1vSQTupjNb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dW2o2g1vSQTupjNb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dW2o2g1vSQTupjNb .marker.cross{stroke:#333333;}#mermaid-svg-dW2o2g1vSQTupjNb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dW2o2g1vSQTupjNb p{margin:0;}#mermaid-svg-dW2o2g1vSQTupjNb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dW2o2g1vSQTupjNb .cluster-label text{fill:#333;}#mermaid-svg-dW2o2g1vSQTupjNb .cluster-label span{color:#333;}#mermaid-svg-dW2o2g1vSQTupjNb .cluster-label span p{background-color:transparent;}#mermaid-svg-dW2o2g1vSQTupjNb .label text,#mermaid-svg-dW2o2g1vSQTupjNb span{fill:#333;color:#333;}#mermaid-svg-dW2o2g1vSQTupjNb .node rect,#mermaid-svg-dW2o2g1vSQTupjNb .node circle,#mermaid-svg-dW2o2g1vSQTupjNb .node ellipse,#mermaid-svg-dW2o2g1vSQTupjNb .node polygon,#mermaid-svg-dW2o2g1vSQTupjNb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dW2o2g1vSQTupjNb .rough-node .label text,#mermaid-svg-dW2o2g1vSQTupjNb .node .label text,#mermaid-svg-dW2o2g1vSQTupjNb .image-shape .label,#mermaid-svg-dW2o2g1vSQTupjNb .icon-shape .label{text-anchor:middle;}#mermaid-svg-dW2o2g1vSQTupjNb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dW2o2g1vSQTupjNb .rough-node .label,#mermaid-svg-dW2o2g1vSQTupjNb .node .label,#mermaid-svg-dW2o2g1vSQTupjNb .image-shape .label,#mermaid-svg-dW2o2g1vSQTupjNb .icon-shape .label{text-align:center;}#mermaid-svg-dW2o2g1vSQTupjNb .node.clickable{cursor:pointer;}#mermaid-svg-dW2o2g1vSQTupjNb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dW2o2g1vSQTupjNb .arrowheadPath{fill:#333333;}#mermaid-svg-dW2o2g1vSQTupjNb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dW2o2g1vSQTupjNb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dW2o2g1vSQTupjNb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dW2o2g1vSQTupjNb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dW2o2g1vSQTupjNb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dW2o2g1vSQTupjNb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dW2o2g1vSQTupjNb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dW2o2g1vSQTupjNb .cluster text{fill:#333;}#mermaid-svg-dW2o2g1vSQTupjNb .cluster span{color:#333;}#mermaid-svg-dW2o2g1vSQTupjNb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dW2o2g1vSQTupjNb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dW2o2g1vSQTupjNb rect.text{fill:none;stroke-width:0;}#mermaid-svg-dW2o2g1vSQTupjNb .icon-shape,#mermaid-svg-dW2o2g1vSQTupjNb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dW2o2g1vSQTupjNb .icon-shape p,#mermaid-svg-dW2o2g1vSQTupjNb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dW2o2g1vSQTupjNb .icon-shape .label rect,#mermaid-svg-dW2o2g1vSQTupjNb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dW2o2g1vSQTupjNb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dW2o2g1vSQTupjNb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dW2o2g1vSQTupjNb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
是
否
否
编译程序
加入-g选项
启动GDB
gdb ./程序名
设置断点
break 行号/函数名
运行程序
run
程序是否在断点处暂停?
检查程序状态
print变量/backtrace调用栈
单步执行或继续
next/step/continue
是否发现Bug?
修复代码
继续调试至结束
程序运行结束
或崩溃
分析崩溃信息
或正常退出
1. 编译程序时加入调试信息
这是使用 GDB 的前提 。必须使用 gcc 或 g++ 编译时加上 -g 选项,才能生成包含调试符号(变量名、行号等)的可执行文件。
bash
# 示例:编译 test.cpp 生成带调试信息的可执行程序 test
g++ -g test.cpp -o test
2. 启动 GDB 并加载程序
在终端中输入 gdb 加上你的可执行程序路径即可启动。
bash
gdb ./test
也可以直接在 GDB 中使用 file 命令加载程序:
gdb
(gdb) file ./test
3. 设置断点
使用 break 命令(简写为 b)设置断点,程序运行到此处会暂停。
gdb
(gdb) break main # 在 main 函数入口处设置断点
(gdb) b 15 # 在第 15 行设置断点
(gdb) b my_function # 在 my_function 函数入口设置断点
4. 运行程序
使用 run 命令(简写为 r)启动程序。程序会一直运行直到遇到断点。
gdb
(gdb) run
如果程序需要参数,可以在 run 后面直接跟上参数:
gdb
(gdb) run arg1 arg2
5. 检查程序状态
程序暂停后,你可以使用各种命令检查其状态:
-
查看变量值 :
print(简写为p)gdb(gdb) print sum $1 = 10 (gdb) p *array@10 # 查看数组array前10个元素 -
查看调用栈 :
backtrace(简写为bt),了解函数调用关系gdb(gdb) backtrace #0 main () at test.cpp:15 -
查看局部变量 :
info locals -
查看内存内容 :
x命令
6. 控制程序执行
- 单步执行(不进入函数) :
next(简写为n) - 单步执行(进入函数) :
step(简写为s) - 继续运行到下一个断点 :
continue(简写为c) - 执行完当前函数 :
finish
7. 修改变量并测试
可以在调试过程中修改变量的值,以测试不同的执行路径或修复方案。
gdb
(gdb) set var i = 5 # 将变量 i 的值修改为 5
🐛 使用 GDB 分析程序崩溃(如段错误)
当程序崩溃(如出现 Segmentation fault)时,GDB 是事后分析的利器。
-
直接调试崩溃程序 :用 GDB 运行程序,当其崩溃时,GDB 会自动捕获并暂停。此时使用
bt命令查看崩溃时的调用栈 ,能立即定位到出问题的函数和行号。gdb(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 -
分析 Core Dump 文件 :如果系统生成了 core dump 文件(通常在崩溃时自动生成),可以用 GDB 加载它来复盘崩溃现场。
bashgdb ./test core # 加载可执行程序和 core 文件 (gdb) bt # 查看崩溃时的调用栈
💡 GDB 使用技巧与进阶
-
查看源代码 :
list(简写为l) 命令可以查看源代码。gdb(gdb) list # 查看当前位置附近的代码 (gdb) list 15 # 查看第15行附近的代码 (gdb) list main # 查看 main 函数的代码 -
观察点(Watchpoint) :
watch命令可以设置观察点,当某个表达式的值发生变化时程序暂停,非常适合追踪变量被意外修改的情况。 -
条件断点 :设置断点时可以附加条件,只有条件满足才暂停,极大提高调试效率。
gdb(gdb) break 10 if i == 5 # 当 i 等于 5 时,在第10行暂停 -
使用
.gdbinit文件 :可以在用户主目录下创建.gdbinit文件,写入常用的 GDB 命令,GDB 启动时会自动执行,避免重复输入。 -
图形化前端 :如果觉得纯命令行不便,可以使用基于 GDB 的图形化或文本前端工具,如 cgdb(分屏显示源码和命令)、DDD 等。
⚠️ 注意事项
- 务必使用
-g编译 :忘记加-g选项会导致 GDB 无法显示源代码行号和变量名,几乎无法调试。 - 优化与调试信息 :在编译时使用
-O优化选项(如-O2)可能会打乱代码顺序,使调试变得困难。调试时建议关闭优化或使用-Og(优化调试体验)。 - GDB 与 IDE 调试器:VS Code、CLion 等 IDE 的调试功能底层通常也是调用 GDB 或 LLDB,它们提供了更友好的图形界面。
📚 总结与学习资源
GDB 是 Linux 环境下 C/C++ 开发者必备的核心技能。它虽然基于命令行,但功能强大,灵活性远超许多图形化调试器。
💡 学习建议 :从最基础的
run、break、next、backtrace命令练起,结合实际调试一个小程序,很快就能上手。遇到具体问题再查阅手册学习新命令。
- 官方手册 :
info gdb或在线手册 GDB Documentation 是最权威的参考。 - 实践练习:多写几个有 Bug 的小程序(如数组越界、空指针解引用、死循环),用 GDB 去定位和修复它们,这是最快的掌握方式。
- 推荐教程 :
- 《GDB Pocket Reference》
- 许多优秀的 Linux C/C++ 开发书籍都有专门的 GDB 章节。
掌握 GDB,你就能从"程序能跑通"进化到"程序为什么能跑通/跑崩",真正理解程序的内部世界。