【问题标题】:gcc - gdb - pretty print stlgcc - gdb - 漂亮的打印 stl
【发布时间】:2012-06-09 11:23:08
【问题描述】:

我目前正在对 STL 进行一些研究,尤其是在调试期间打印 STL 内容。我知道有很多不同的方法。

喜欢:

我目前正在寻找的是,为什么 g++ 会删除未使用的函数,例如我有以下代码并使用编译设置g++ -g main.cpp -o main.o

include <vector>
include <iostream>
using namespace std;
int main() {
    std::vector<int> vec;
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);

    return;
}

所以当我调试这段代码时,我会发现我不能使用print vec.front()。我收到的消息是:

Cannot evaluate function -- may be inlined

因此我尝试使用设置-fkeep-inline-functions,但没有任何更改。

当我使用nm main.o | grep front 时,我看到方法.front() 没有行条目。再次做同样的事情,但在我的代码中有一个额外的vec.front() 条目,我可以使用print vec.front(),并在我看到该条目的地方使用nm main.o | grep front

0000000000401834 W _ZNSt6vectorIiSaIiEE5frontEv

谁能解释我如何将所有函数保留在我的代码中而不会丢失它们。我认为,只要我不设置优化设置或执行以下操作,死函数就不会被删除。

为什么需要它:当前的 Python 实现使用内部 STL 实现来打印容器的内容,但使用 ISO/IEC 14882 定义的函数会更有趣。我知道可以编写一个共享库,可以在调试之前将其编译为您的实际代码,以保持您拥有所有 STL 函数,但谁想在调试之前为其代码编译一个额外的库。了解这两种方法(Shared Lib. 和 Python)是否有一些优点和缺点也会很有趣?

【问题讨论】:

  • 您的问题已经得到答案:stackoverflow.com/a/7241548/184968."Partial instantiation" : ... only the member functions that are used are instantiated. The following is well-formed code:。我的意思是你问的是“死函数”,但 std::vector::front() 是模板的成员。它没有被删除,甚至没有在您的示例中创建。
  • 抱歉造成误会。在段落中“当我使用”nm main.o | grep front" 等...,我试图说,在我的代码中使用 vec.front() 之后,我可以在 gdb 中使用该函数。究竟什么是死函数,不是一个函数在我的源代码中可用但没有使用??另一个问题 gdb 是否知道函数 .front(),即使我没有使用它,但没有调试信息?

标签: debugging function stl gdb g++


【解决方案1】:

究竟什么是死函数,它不是在我的源代码中可用但未被使用的函数吗?

有两种情况需要考虑:

int unused_function() { return 42; }
int main() { return 0; }

如果你编译上面的程序,unused_function 是死的——永远不会被调用。但是,它仍然会出现在最终的可执行文件中(即使经过优化 [1])。

现在考虑一下:

template <typename T> int unused_function(T*) { return 42; }
int main() { return 0; }

在这种情况下,unused_function出现,即使您关闭了所有优化。

为什么?因为模板不是“真正的”功能。它是一个原型,编译器可以从中创建“真正的”函数(称为“模板实例化”)——每个类型都有一个 T。由于您从未使用过unused_function,因此编译器没有创建它的任何“真实”实例。

您可以使用explicit instantiation request 请求编译器显式实例化给定类中的所有函数,如下所示:

#include <vector>
template class std::vector<int>;

int main() { return 0; }

现在,即使 没有vector 函数被使用,它们也全部被实例化为最终的二进制文件。

[1] 如果您使用的是 GNU ld(或 gold),在这种情况下,您仍然可以通过使用 -ffunction-sections 编译并使用 -Wl,--gc-sections 链接来摆脱 unused_function

【讨论】:

    【解决方案2】:

    感谢您的回答。再说一遍,模板函数不会由 gcc 启动,因为它们是原型。只有在使用该函数或它被显式启动时,它才会在我的可执行文件中可用。

    所以我们之前提到的是:

    • 函数定义int usedFunc() { return 10; }
    • 函数原型 int protypeFunc();(只是为了分解)

    当你内联函数时会发生什么?我一直认为,该函数将被插入到我的源代码中,但现在我读到,编译器通常会自行决定要做什么。 (听起来很奇怪,因为它们必须是规则)。例如,您是否使用关键字 inline 并不重要。

    inline int inlineFunc() { return 10; }
    

    我的一个朋友也告诉我,他无法访问函数的地址,尽管他没有使用内联。有没有我忘记的函数类型?他还告诉我,他们应该是对象数据格式的差异。

    @edit - 忘记了:

    • 嵌套函数
    • 函数指针
    • 重载函数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多