结论:用 gcc -g 编译 + gdb 命令行即可高效调试,关键在于编译时加 -g(推荐 -g3)且避免 -O2 等优化干扰;若 gdb 提示“No symbol table”,说明未嵌入调试信息,需用 file 或 readelf 验证;函数断点失败常见于拼写错误、inline 或路径问题;step 易陷入库函数,应多用 next/finish;print 失败多因变量越界或未解引用;调试核心是建立“预期 vs 实际”的对照。

直接说结论:不用装一堆插件、不用配 IDE,用 gcc -g 编译 + gdb 命令行就能开始有效调试 —— 关键是编译时别漏掉 -g,否则 gdb 什么都看不到。
为什么 gdb 启动后显示 “No symbol table is loaded”
这是新手最常卡住的第一步。根本原因不是 gdb 没装好,而是可执行文件里压根没嵌入调试信息。
-
gcc默认不生成调试符号,必须显式加-g(推荐用-g3,包含宏和内联信息) - 如果用了优化选项(比如
-O2),即使加了-g,gdb 也可能跳行、变量显示为<optimized out></optimized> - 验证方法:编译后运行
file your_program,输出里有with debug_info才算成功;或者用readelf -S your_program | grep debug看是否有.debug_*段
gdb 里 set breakpoint 总是提示 “Function not defined”
常见于函数名拼错、函数被 inline 或未暴露符号,也可能是源码路径不对。
- 先用
info functions列出所有已知函数,确认名字是否匹配(C++ 函数名会被 mangling,可用info functions "add"模糊查) - 如果函数在头文件里定义且加了
inline,gdb默认看不到 —— 编译时加-fno-inline临时禁用 - 源码移动过或不在当前目录?启动 gdb 时用
gdb -directory /path/to/src your_program告诉它去哪找源文件 - 断点设在库函数(如
printf)上?得先catch syscall write或用break *printf(需符号表支持)
单步执行(step)卡在 libc 里出不来
这不是 bug,是 step 进入了系统调用或库内部,而你通常只关心自己写的代码。
- 用
next(简写n)代替step(简写s):它会“跨过”函数调用,不进入函数体 - 想跳回自己的代码?用
finish退出当前函数,再next - 实在陷进去了,用
frame看当前栈帧,up/down切换层级,bt查完整调用栈 - 如果连
next都卡住,检查是否在汇编层 —— 运行layout src切回源码视图,或set disassemble-next on关闭自动反汇编
print 变量显示 “Cannot access memory at address …”
说明变量已经超出作用域、被优化掉,或地址非法 —— 不是内存泄漏的直接证据,但提示你正在看一个“不存在”的东西。
- 局部变量在函数 return 后立即失效,
print它必然失败;确保在函数内、变量声明后、作用域结束前查看 -
info locals能列出当前栈帧所有可见局部变量,比盲目print更可靠 - 指针变量要加
*才解引用:print *ptr,否则只打地址 - 结构体成员访问用点号:
print my_struct.field;数组用方括号:print arr[0]
真正容易被忽略的点:调试不是“跑一遍看哪行崩”,而是建立“预期 vs 实际”的对照。每次 next 或 print 前,先想清楚“这一步该发生什么”,再验证。否则 gdb 再熟,也只是在看一堆跳动的指令地址。


















