GDB断点命中后需分层查验:先用l确认停靠位置,再用p查变量(注意作用域)、bt或frame查调用栈、x/p解引用查内存,避免误判问题层级。

断点命中后,GDB 停在目标位置,但“现场”不是自动展开的——你得主动查,而且要分层次查:当前上下文、变量值、调用链、内存状态。不查清楚,很容易误判是哪一层出的问题。
查看当前源码和执行位置
断点停住后第一反应不该是 print,而是确认「到底停在哪」。GDB 默认不一定显示源码(尤其没加载符号或路径不对时),l(list)是最直接的验证手段:
-
l单独执行:显示当前行及前后几行,确认是否真停在预期位置 -
l 20或l main:跳转到指定行或函数,避免被错位的断点误导 - 如果报错
No symbol table is loaded,说明没带调试信息编译(gcc -g忘了加)或dir没设对源码路径
打印局部/全局/同名变量的值
变量作用域容易混淆,尤其当局部变量和全局变量重名时,p var 默认输出的是局部变量——这不是 bug,是 GDB 的作用域规则:
-
p var:优先取当前栈帧的局部变量 -
p ::var:强制访问全局变量(C/C++ 中未限定命名空间的全局变量) -
p 'file.c'::var:指定文件中的全局变量,适用于多文件工程 -
p this->member:C++ 成员变量,注意this必须有效(不能在 static 函数里用) - 如果变量是优化掉的(如
gcc -O2),p可能报<optimized out></optimized>,这时得关优化重编译
切换栈帧并检查各层变量
单靠当前帧的变量看不出调用链问题。比如崩溃前某层传了错误指针,但当前帧里指针已经解引用过了——必须往上翻:
-
bt:看完整调用栈,但只显示函数名和地址 -
bt full:每层都打印局部变量,信息量大但可能刷屏 -
frame 2:跳到第 2 层栈帧(编号从 0 开始),再info locals查该层所有局部变量 -
up/down:逐层移动,比记编号更安全,尤其栈很深时 - 注意:某些帧可能因尾调用或内联而丢失变量,
bt full也打不出,这时候得看汇编 + 寄存器(info registers)
验证指针、数组和内存内容
很多问题本质是内存异常:野指针、越界、未初始化——光看变量名没用,得看它指向的内存实际是什么:
-
p *ptr:解引用一次,适合普通指针;若 ptr 是int**,得p **ptr -
p *ptr@5:查看 ptr 指向的连续 5 个元素(@是数组操作符,不是 C 语法) -
x/5xw ptr:用x命令原生读内存,5xw表示 5 个字(word),十六进制显示,绕过类型系统,查原始数据 -
x/10cb ptr:查 ptr 后 10 字节的字符(含 \0),适合验证字符串内容 - 如果
ptr是空或非法地址,p *ptr会报Cannot access memory,但x有时还能读出部分合法区域,更鲁棒
真正难的不是命令怎么输,而是知道该查哪一层、该信哪个值。比如 bt full 显示某变量是 0,但 x 发现它指向的内存全是 0xcccccccc(Visual Studio 调试填充),说明根本没初始化——这种细节,只有动手翻过内存才记得住。


















