【问题标题】:How does backtrace work?回溯如何工作?
【发布时间】:2012-01-30 20:02:39
【问题描述】:
#include <iostream>
using namespace std;

class dummyA
{
    int x;
    public:
        dummyA ()
        {
            x = 0;
        }

        void test ()
        {
            x++;
        }
};

int main ()
{
    cout << "\nG'Morning";
    dummyA obj;
    obj.test ();
    return 0;
}

回溯输出:

(gdb) bt
#0  main () at backtrace.cpp:21
(gdb) bt full
#0  main () at backtrace.cpp:21
        obj = {x = -8896}
(gdb) n

22              dummyA obj;
(gdb) 

问题:

  • 据说bt 正在打印整个堆栈的回溯:堆栈中所有帧每帧一行,但我在输出中只看到函数的名称?为什么呢?
  • bt full 显示内部工作,当控件不在该行(dummyA obj;)时如何读取'obj'?

编辑 1:

Breakpoint 1, dummyA::testB (this=0x7fffffffdc50) at backtrace.cpp:20
20                              x = x + 2;
(gdb) bt 0
(More stack frames follow...)
  • 上面的输出什么也没显示,因为被调用函数 testB 的局部变量为零?对吗?
(gdb) bt 1
#0  dummyA::testB (this=0x7fffffffdc50) at backtrace.cpp:20
(More stack frames follow...)

(gdb) bt 2
#0  dummyA::testB (this=0x7fffffffdc50) at backtrace.cpp:20
#1  0x000000000040078b in main () at backtrace.cpp:31
  • 第 1 帧和第 2 帧究竟显示了什么?

(gdb) bt 已满
#0 main () 在 backtrace.cpp:26
obj1 = {x = -8896}
obj2 = {x = 0}

  • 假设断点在 main 上,为什么 x 这里有两个不同的值?

编写以下代码:

#include <iostream>
using namespace std;

class dummyA
{
    int x;
    public:
        dummyA ()
        {
            x = 0;
        }

        void testA ()
        {
            x = x + 1;
        }

        void testB ()
        {
            x = x + 2;
        }
};

int main ()
{
    cout << "\nG'Morning";
    dummyA obj1;
    dummyA obj2;

    obj1.testA ();
    obj1.testB ();

    obj2.testA ();
    obj2.testB ();

    return 0;
}

【问题讨论】:

    标签: c++ linux gdb


    【解决方案1】:

    bt 据说正在打印整个堆栈的回溯:堆栈中的所有帧每帧一行,但我在输出中只看到函数的名称?为什么会这样?

    回溯显示当前函数,然后是调用该函数的函数,以此类推,一直返回到main()。每个“堆栈帧”是特定函数使用的堆栈部分,因此每个函数都有一个帧。由于当前函数main(),所以只有一帧要显示。

    (也许您希望回溯可以让您看到已执行的每一行代码。不幸的是,当正常运行代码时(这是gdb 所做的,除了添加断点),没有足够的可用的信息来做到这一点;你能做的最好的就是查看函数调用的历史。)

    bt full 显示内部工作,当控件不在该行(dummyA obj;)时如何读取'obj'?

    已为对象分配空间(在本地堆栈帧中);它只是还没有被初始化。您会看到该空间中发生的任何事情,如果您跨过初始化行,它应该变成{x = 0}

    上面的输出什么都没有显示,因为被调用函数testB 的局部变量为零?对吗?

    它什么也不显示,因为你要求它什么也不显示; bt 的参数指定要显示多少堆栈帧,你说的是零。

    第 1 帧和第 2 帧究竟显示了什么?

    在第一种情况下,您要求一个堆栈帧;当前函数的那个​​。它告诉你你在函数dummyA::testB中,它被调用的对象的地址(this)是0x7fffffffdc50,对应的源代码行是backtrace.cpp的第20行。

    在第二种情况下,您请求了两个帧,因此它还显示了当前函数的调用位置:函数main()backtrace.cpp 的第 31 行源代码。

    假设断点在main上,为什么x这里有两个不同的值?

    每个都是不同对象(obj1.xobj2.x)的成员,并且都没有被初始化;所以每个都显示了一些恰好位于该内存位置的随机值。同样,如果您跨过初始化程序,两者都将变为零。

    【讨论】:

      【解决方案2】:

      对象尚未构造,但已为其分配空间。您会看到整个回溯——您在main,句号。

      【讨论】:

      • 为什么指定you're in main?这与查看整个回溯有什么关系?
      • 顺便说一句,你没有对第一个问题说什么。
      • @AnishaKaul:因为只有一帧。 main() 的框架是第一个被调用的函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 2015-10-26
      相关资源
      最近更新 更多