必须加-g才能调试,因为-g使编译器嵌入DWARF调试信息,让GDB映射机器指令到源码行号、变量名和函数名;不加-g则仅见汇编与内存地址,无法设行断点、查变量或显示源码。

直接用 g++ -g 编译,再用 gdb 调试,这是唯一可靠路径。别指望不加 -g 就能单步看变量。
为什么必须加 -g 才能调试
没有 -g,gdb 看不到源码行号、局部变量名、函数参数,甚至无法设置行断点——它只面对一堆机器指令和寄存器。加了 -g 后,编译器会在目标文件里嵌入 DWARF 调试信息,gdb 才能映射汇编指令回 main.cpp 的第 12 行。
常见错误现象:gdb ./app 启动后输入 list 显示 “No symbol table is loaded”,或 print x 报错 “No symbol ‘x’ in current context”。
-
-g不影响运行性能,只增大可执行文件体积(通常几 KB 到几百 KB) - 不要混用
-g和-O2或更高优化等级:变量可能被寄存器优化掉,gdb显示<optimized out></optimized> - 调试时推荐组合:
g++ -g -O0 main.cpp -o app_debug
gdb 最小可用调试流程
不是所有命令都要记,掌握这 4 个就能定位绝大多数逻辑问题:
立即学习“C++免费学习笔记(深入)”;
-
break main或b 15—— 在入口或某行设断点 -
run(可简写为r)—— 启动程序,停在第一个断点 -
next(n)—— 单步执行,不进入函数内部;step(s)—— 进入函数 -
print x(p x)—— 查看变量值;bt—— 查看调用栈
注意:gdb 默认不读取 C++ 标准库符号(比如 std::vector 的内部结构),如需展开 STL 容器,启动时加 --interpreter=mi2 或手动加载 libstdc++.so 的 debuginfo 包(Ubuntu/Debian 上是 libstdc++6-<version>-dbg</version>)。
调试多文件 C++ 项目时的坑
只要有一个 .cpp 文件没用 -g 编译,对应源码就无法调试——gdb 只认目标文件(.o)里有没有调试信息,不认你“以为”加了。
- 用
make时,确保CXXFLAGS包含-g,例如:CXXFLAGS = -g -std=c++17 - 用
cmake时,必须指定构建类型:cmake -DCMAKE_BUILD_TYPE=Debug ..,否则默认是Release,-g不会自动加 - 检查是否真带调试信息:
file app输出含 “with debug_info”,或readelf -S app | grep debug有非空结果
调试时看不到头文件里的内联函数或模板实例
这是正常行为,不是配置错误。GCC 默认把 inline 函数和模板实例化代码直接展开进调用点,不生成独立符号;gdb 没法对它们设断点或 step into。
解决方法有限:
- 临时把内联函数改成普通函数(删
inline关键字),重新编译 - 对模板类,在 .cpp 中显式实例化一次:
template class std::vector<int>;</int>,让符号落地 - 用
gdb的display命令持续观察关键表达式,而非依赖单步
真正麻烦的是跨编译单元的符号缺失——比如 A.h 里定义的 inline void foo(),在 B.cpp 调用,但 A.cpp 没参与链接,gdb 就完全不知道 foo 长什么样。这种时候,得靠日志或 printf 补位。


















