特性 | Debug 版本 | Release 版本 |
---|---|---|
编译选项 | -g(生成调试信息)、-O0(无优化) | -O2(默认优化)、-s(剥离符号) |
符号表 | 完整保留(函数名、变量名、行号) | 仅保留必要符号(用于动态链接) |
文件体积 | 较大(调试信息占比可达 50%+) | 较小(优化后代码更紧凑) |
执行效率 | 慢(无优化且含调试辅助代码) | 快(指令重排、循环展开等优化) |
调试支持 | 完全支持(GDB 精准定位到源码行) | 仅支持有限调试(需手动加载符号表) |
典型用途 | 开发阶段调试、单元测试 | 生产环境部署、用户交付 |
关键反馈节点:
开发阶段:基于 Debug 版快速定位逻辑错误(如空指针、数组越界)
自测阶段:用 Release 版验证性能与资源占用(Debug 版的优化缺失可能掩盖真实问题)
测试阶段:通过核心转储(Core Dump)分析生产环境 Crash 时,需依赖 Debug 符号表
精准定位问题根源
验证程序逻辑正确性:调试器支持单步执行(step)、条件断点(break if i>100),允许开发者逐行验证分支逻辑、循环
优化代码可读性与可维护性:debug 阶段暴露的问题(如复杂函数逻辑)促使开发者重构代码,间接提升代码质量;断言(assert())在 Debug 版生效,强制检查前置条件(如指针非空),提前暴露潜在风险
衔接测试与生产环境
# 基础调试配置(必备)
gcc -g -o debug_program source.c # C语言编译
g++ -g -o debug_program source.cpp # C++语言编译
注意:默认情况下(不加 -g),gcc/g++ 生成 release 版
# 检查符号表(含函数名/变量名)
nm debug_program | grep main # 应显示main函数地址与符号名
# 对比Release版(无符号表时仅显示地址)
nm release_program | grep main # 可能显示 T 0x400550(无符号名)
gdb debug_program # 调试可执行文件
命令 | 全称 | 功能描述 | 示例 |
---|---|---|---|
l | list | 显示源码(默认 10 行,可指定行号 / 函数名) | l 50 显示第 50 行附近代码;l main 显示 main 函数 |
b | break | 设置断点(行号 / 函数名 / 条件表达式) | b 100 在第 100 行设断点;b myfunc if x>10 条件断点 |
r | run | 运行程序(可带参数) | r input.txt 以 input.txt 为参数运行程序 |
n | next | 逐过程,单步执行(跳过函数调用) | 在调用函数时,n 会直接执行完整个函数调用 |
s | step | 逐语句,单步执行(进入函数内部) | 调试自定义函数时,s 会进入函数第一行 |
p | 打印变量 / 表达式值 | p *ptr 打印指针指向的值;p arr[5] 打印数组元素 |
|
display | - | 自动显示变量(程序暂停时更新) | display i 每次暂停时显示变量 i 的值 |
undisplay | - | 取消自动显示 | undisplay 1 取消第 1 号自动显示项(info display查看编号) |
bt | backtrace | 查看调用栈(定位函数调用顺序) | 段错误时执行bt ,快速定位出错函数 |
q | quit | 退出调试 | q 退出 gdb 会话 |
set var | set variable | 动态修改变量值(在调试过程中临时赋值,影响程序运行逻辑) | set var i=10 将变量 i 的值强制设为 10;set *ptr=0x1234 修改指针指向的内存值 |
finish | - | 继续运行直到当前函数返回(跳出当前函数,查看返回值) | 在 step 进入子函数后,执行 finish 直接运行到函数返回并停在调用行 |
gdb 内置命令历史机制,可自动记录最近执行的命令,在完成一条命令后直接按下回车键,即可快速重复执行上一条命令。
示例:(gdb) next # 第一次输入next命令,单步执行程序 Breakpoint 1, main () at test.c:10 10 int x = 5; (gdb) # 直接回车,重复执行上一条命令(next) 11 x += 3; (gdb) # 再次回车,继续重复执行next 12 printf("x = %d\n", x);
b
是 break
命令的缩写,是 gdb 中 设置断点(Breakpoint) 的核心指令。
❶ 行号断点:最直接的位置标记
语法:b [行号] 或 break [行号]
作用:在当前文件的指定源码行号处设置断点,程序运行到该行时暂停。
(gdb) b 100 # 在当前文件第100行设置断点
(gdb) break test.c:50 # 在test.c文件的第50行设置断点(跨文件指定)
❷ 函数断点:按逻辑单元定位
语法:b [函数名] 或 break [函数名]
作用:在函数入口处设置断点,包括自定义函数、库函数或系统调用。
(gdb) b main # 在程序入口main函数处设置断点(程序启动后首次暂停)
(gdb) break printf # 在调用标准库函数printf时暂停(需保留符号表)
(gdb) b mymodule.c:myfunc # 在mymodule.c文件的myfunc函数入口处暂停
优势:无需关心具体行号,直接按函数边界控制执行流,适合模块化调试(如快速定位某个功能函数的逻辑起点)。
语法:b [行号或函数名] if [条件表达式]
作用:仅当条件表达式为真时,断点才生效(避免每次执行到断点都暂停,提升调试效率)。
(gdb) b 200 if i==100 # 当循环变量i等于100时,在第200行暂停(跳过前99次循环)
(gdb) break myfunc if *ptr==NULL # 当指针ptr为空时,在myfunc函数入口暂停(定位空指针异常)
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005a3 in main at test.c:10
2 watchpoint keep y 0x00007fffffffde40 array[5]
(gdb) disable 2 # 禁用编号为2的内存断点(暂时忽略,保留配置)
(gdb) enable 1 # 重新启用编号为1的行断点(无需重新设置条件)
ps.命令缩写:d [编号]
(gdb) delete 1 # 删除编号为1的行断点
(gdb) delete # 删除所有断点(需确认提示)
(gdb) d <断点编号> # 例:d 3 (等价于 delete 3)
(gdb) delete # 不加编号时,删除所有断点(谨慎使用!)
断点编号的「线性增长」特性
GDB 内部维护一个 全局唯一的断点编号计数器,具备以下特性:
(gdb) break main.c:10 # 断点1
(gdb) break main.c:20 # 断点2
(gdb) delete 2 # 删除断点2
(gdb) break main.c:30 # 新断点编号为3(而非2)
(gdb) info breakpoints
# 输出:Num 1, 3(断点2已删除)
END