必须加-g,否则GDB报“No symbol table is loaded”;-O0最利于调试,可避免变量优化消失、单步异常等问题;-g与-O可共存但需谨慎,日常开发推荐-g -O0。

-g 是必须的,其他参数取决于你调试时是否需要保留原始代码行为
为什么一定要加 -g
没有 -g,GDB 启动后会报错:No symbol table is loaded. Use the "file" command。这是因为可执行文件里压根没有函数名、变量名、行号这些信息,GDB 看不到源码对应关系,连 list 都显示不了。哪怕你只用 gdb ./main 进去,第一步就卡住。
-O0 是调试阶段最稳妥的选择
优化等级会影响调试体验:编译器可能把变量优化掉、合并语句、内联函数、甚至删掉整段“没用”的逻辑。这时你在 GDB 里 print x 可能提示 No symbol "x" in current context,或者 step 直接跳过某行——不是你漏写了,是它被优化没了。
-
-O0:关闭所有优化,代码结构和源码基本一一对应,单步、断点、变量查看都最可靠 -
-Og:GCC 推荐的“调试友好型优化”,在-O0和-O1之间,保留大部分调试信息,但可能仍导致少量变量不可见 -
-O1及以上:不建议用于日常调试;-O2或-O3下,next和step行为可能反直觉,backtrace栈帧也可能被裁剪
可以和 -g 共存但需谨慎的选项
-g 和 -O 系列并不互斥,GCC 允许同时使用,比如 g++ -g -O2 main.cpp -o main 能通过编译,但实际调试时容易踩坑:
立即学习“C++免费学习笔记(深入)”;
-
-g -O2常见问题:局部变量突然“消失”,watch失效,step跳入汇编而非 C++ 源码 -
-g -O3更激进,可能触发自动向量化或函数重排,break main甚至停不到你预期的位置 - 真正需要性能验证时再用带优化的调试,平时开发阶段坚持
-g -O0,省下反复猜变量去哪儿的时间
其他影响调试的编译细节
有些看似无关的选项,也会让 GDB 行为异常:
- 不要用
-gg:老式写法,现代 GCC 已不支持,会生成无效调试信息 - 多文件项目记得每个
.cpp都加-g,否则break other.cpp:42会失败 - 如果用了
-fPIE或-pie(常见于 Ubuntu 默认链接),GDB 仍可调试,但info proc mappings看到的地址是动态的,不影响基础操作 - 发布前去掉
-g:调试符号会显著增大二进制体积,且暴露内部函数名和路径
最常被忽略的一点:改了编译参数后,别忘了 make clean && make 或手动删掉旧的 .o 和可执行文件——否则你以为加了 -g,其实链接的是上次没带调试信息的老目标。


















