Cxxdroid 中文文档 下载 App

变量检查与调用栈 —— bug 的现场取证

变量检查

程序停在断点时,所有当前作用域内的变量都可以查看。

基本类型

int count = 42;              ← 显示 count = 42
double ratio = 3.14159;      ← 显示 ratio = 3.14159
bool active = true;          ← 显示 active = true
char *msg = "hello";         ← 显示 msg = "hello"

指针

Node *node = getHead();      ← 显示 node = 0x7abc1234
                                如果 node 不是 null,点击展开可以看 node->data 等成员

STL 容器

部分 Cxxdroid 版本可能对 STL 容器的显示不太友好——gdb 需要 Python pretty printer 支持才能把 std::vector<int>{1, 2, 3} 正确展开显示。如果显示成一堆内部迭代器或分配器对象,属正常现象。

自定义结构体 / 类

struct User {
    int id;
    std::string name;
    float score;
};
User u = {1, "Alice", 95.5};

点击 u 可以展开看到三个成员各自的值。

调用栈(Call Stack)

调用栈记录了从程序入口到当前断点的函数调用链:

[0] getUserProfile(userId=42)        ← 当前停在这里
[1] loadUserData(userId=42)         ← getUserProfile 的调用者
[2] handleHttpRequest(request=...)   ← loadUserData 的调用者
[3] main()                           ← 程序入口

从下往上看:main 调了 handleHttpRequest,后者调了 loadUserData,后者又调了 getUserProfile——你就在 getUserProfile 里。

调用栈的两个用途

回溯调用者:你当前在某个深嵌套的函数里,想看看到底是谁调进来的。点击调用栈里的某一帧(比如 [1] loadUserData),调试器会跳回到那一行——你就能看到 loadUserData 当时的局部变量和参数值。

定位空指针来源:程序在 deref(ptr) 崩了,调用栈显示是从 processOrder → loadUser → deref 过来的。到 loadUser 那一帧看,ptr 在传给 deref 之前就是 null 了——说明问题在 loadUser 里,不是 deref 本身。

查看数组 / 内存

gdb 可以直接查看一段内存区域的值:

int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

调试面板里点击 arr,应该能看到 10 个元素的值。如果看到的只是数组首地址,可以尝试手动添加 Watch 表达式:arr[0]@10(gdb 特定语法)。

Watch 窗口

Watch 窗口允许你手动添加任意表达式来持续观察:

表达式的值会随着单步执行实时更新——每 Step 一次就刷新一次。

如果 Cxxdroid 版本没有独立的 Watch 面板,试试在变量查看区域找「添加表达式」按钮。

常见坑

编译器优化导致变量被优化掉

如果 Debug 模式没正确关闭优化(-O2),编译器可能把某些变量直接优化进寄存器、甚至直接消除。此时调试面板里会显示 <optimized out>,意思是「这个变量在编译后已经不存在了」。

解决方法:在 Debug 构建配置里确认:

STL 容器显示乱码

如前所述,gdb 需要 pretty printer 才能正确显示 STL 容器。如果显示成内部实现细节,可以:

指针显示地址但不显示值

ptr = 0x12345678 能看到地址,但展开后成员显示 <memory unavailable>——要么地址无效(野指针)、要么指针类型不对。