在 Linux 环境下进行 C/C++ 程序开发,调试是定位问题、保障代码质量的核心环节。GDB(GNU Debugger)作为一款功能强大的命令行调试工具,能够帮助开发者跟踪程序执行流程、监控变量变化、定位崩溃原因。本文将基于基础开发工具知识点,系统梳理 GDB 的核心操作的知识点,从环境准备到高级技巧,助力快速掌握调试技能。
一、GDB 调试前提
GDB 调试的核心是依赖程序中的调试信息,而 GCC/G++ 默认生成的二进制程序为 Release 模式,不包含调试信息,无法直接调试。因此,编译时需添加-g选项,生成带调试信息的 Debug 版本程序。
编译命令对比
# 默认Release模式(无调试信息,无法GDB调试)
gcc mycmd.c -o mycmd
# Debug模式(含调试信息,支持GDB调试)
gcc mycmd.c -o mycmd -g
验证调试信息
通过file命令可验证程序是否包含调试信息:
# 带调试信息的程序会显示 "with debug_info"
file mycmd
# 输出示例:mycmd: ELF 64-bit LSB shared object, ..., with debug_info, not stripped
二、GDB 基础操作流程
1. 启动与退出 GDB
| 操作 | 命令 | 说明 |
|---|---|---|
| 启动调试 | gdb 可执行文件名 |
如 gdb mycmd,进入 GDB 交互环境 |
| 退出调试 | quit 或 Ctrl + d |
退出 GDB,中断程序运行 |
2. 核心调试命令(必掌握)
GDB 的核心命令可满足日常调试需求,以下是高频使用场景及示例:
| 命令 | 简写 | 功能描述 | 示例 |
|---|---|---|---|
| 查看源代码 | list | 从当前位置列出 10 行代码,重复执行继续向下 | list(默认)、list 10(从第 10 行开始) |
| 查看指定函数代码 | list 函数名 | 列出目标函数的完整源代码 | list main(查看 main 函数) |
| 运行程序 | run | 从程序开头连续执行,直到断点或结束 | run(简写 r) |
| 单步执行(不进函数) | next | 逐过程执行,跳过函数内部(类似 F10) | next(简写 n) |
| 单步执行(进函数) | step | 逐语句执行,进入函数内部(类似 F11) | step(简写 s) |
| 设置断点 | break | 在指定行 / 函数设置断点 | break 20(第 20 行)、break Sum(Sum 函数开头) |
| 查看断点信息 | info break | 列出所有断点的编号、位置、状态 | info break(简写 info b) |
| 继续执行 | continue | 从当前位置继续执行,直到下一个断点 | continue(简写 c) |
| 打印变量 / 表达式 | 输出变量值或表达式结果 | print result(打印变量)、print start+end(表达式) |
|
| 修改变量值 | set var | 调试中动态修改变量值,验证逻辑 | set var i=10(将变量 i 设为 10) |
| 跟踪变量 | display | 每次程序停止时自动打印变量值 | display result(跟踪 result 变量) |
| 取消跟踪变量 | undisplay 编号 | 根据display的编号取消跟踪 |
undisplay 1(取消第 1 个跟踪变量) |
| 执行到函数返回 | finish | 执行当前函数剩余代码,直到返回调用处 | 在函数内部执行 finish |
| 查看当前栈帧 | backtrace | 显示函数调用栈,定位当前执行层级 | backtrace(简写 bt) |
| 查看局部变量 | info locals | 列出当前栈帧中的所有局部变量及值 | info locals(简写 i locals) |
3. 断点管理进阶
断点是调试的核心,除基础设置外,还支持条件断点、删除 / 禁用等操作:
| 操作 | 命令 | 示例 |
|---|---|---|
| 删除所有断点 | delete breakpoints |
清空所有断点 |
| 删除指定断点 | delete breakpoints 编号 |
如 delete breakpoints 1(删除 1 号断点) |
| 禁用所有断点 | disable breakpoints |
断点保留但不生效 |
| 启用所有断点 | enable breakpoints |
恢复禁用的断点 |
| 设置条件断点 | break 行号 if 条件 |
break 9 if i==30(第 9 行仅当 i=30 时触发) |
| 给已有断点加条件 | condition 断点编号 条件 |
condition 2 i==30(给 2 号断点加条件) |
三、GDB 高级调试技巧
1. 变量监视(watch 命令)
当需要监控某个变量是否被意外修改时,watch命令可实现 "值变化触发中断",适用于定位变量篡改问题:
# 示例:监视result变量,值变化时暂停
(gdb) watch result # 设置硬件监视点
Hardware watchpoint 2: result
(gdb) c # 继续执行
Continuing.
Hardware watchpoint 2: result
Old value = 0
New value = 1 # 变量变化时触发中断,提示新旧值
Sum (s=1, e=100) at mycmd.c:7
2. 定位逻辑错误(set var 实战)
调试时若发现结果异常,可通过set var动态修改关键变量,快速验证问题原因。例如:
假设程序中flag变量默认值为 0,导致Sum函数返回值为 0,通过修改flag验证逻辑:
(gdb) p flag # 查看变量当前值
$2 = 0
(gdb) set var flag=1 # 动态修改为1
(gdb) n # 继续执行
running done, result is: [1-100]=5050 # 结果正常,确认是flag变量的问题
3. 高效跳转(until 命令)
当需要快速执行到指定行(跳过中间代码)时,使用until 行号,无需逐句单步:
# 从当前位置直接执行到第16行
(gdb) until 16
Sum (s=1, e=100) at mycmd.c:16
16 return result*flag;
4. 分屏调试(cgdb 工具)
原生 GDB 不支持代码分屏显示,可安装cgdb工具增强可视化体验:
# 安装cgdb(CentOS/Ubuntu)
sudo yum install -y cgdb # CentOS
sudo apt-get install -y cgdb # Ubuntu
# 启动分屏调试
cgdb mycmd
- 操作:
ESC切换到代码屏(可浏览源码),i切换回 GDB 命令屏(执行调试命令)。
四、常见问题与注意事项
-
无法设置断点 :确保编译时添加了
-g选项,否则 GDB 无法识别源代码行。 -
中文乱码 :GDB 默认编码与系统一致,若出现乱码,可在启动前设置编码:
export LC_ALL=C。 -
多文件调试 :设置断点时需指定文件名,如
break test.c:15(test.c 第 15 行)。 -
首次使用警告 :首次使用 GDB 会提示设置用户名和邮箱,执行以下命令配置:
git config --global user.name "Your Name" git config --global user.email "your@email.com"
五、调试流程总结
- 编译带调试信息的程序:
gcc -g 源文件 -o 可执行文件; - 启动 GDB:
gdb 可执行文件; - 设置断点:
break 行号/函数名; - 运行程序:
run; - 单步调试 / 查看变量:
next/step/print; - 定位并修复问题,退出 GDB:
quit。