【问题标题】:Does declaring functions in anonymous namespace with "static" reduces the linking time and memory by not polluting the symbol table使用“静态”在匿名命名空间中声明函数是否通过不污染符号表来减少链接时间和内存
【发布时间】:2021-05-03 05:44:54
【问题描述】:

我正在一个代码审查会议中进行讨论。

争论是关于匿名命名空间中的函数是否应该声明为静态的。例如,有人告诉我使用“static”关键字声明的 square3 函数具有优势。

namespace {
int square2(int num) {
    return num * num;
}

static int square3(int num) { 
    return num * num;
}

}

我的同事告诉我静态是有益的,因为:

静态函数不需要函数表中的条目,并且 因此链接时不需要时间或内存。

static 表示链接时不暴露。它改善了链接时间 并减少链接时的内存使用。匿名命名空间不 提供这个。

我认为我的同事所说的“功能表”是指“符号表”。除了另一个S.O question 最不赞成的答案外,我找不到任何关于此的文档

通常最好选择静态链接,因为那样不会 污染符号表

我正在尝试使用编译器资源管理器查看该信息是否正确。但我找不到进入符号表的方法。我看到的所有函数名称和所有内容都在same way 中被破坏。

所以我有两个问题:

1 - 在匿名命名空间中使用带有 static 关键字的函数是否有助于减少内存/链接时间?

2 - 有没有办法在编译器资源管理器中检查符号表?

【问题讨论】:

  • 对于2.您可以添加readelf工具并使用--symbols检查符号表。像这样godbolt.org/z/dsW1xd
  • 非常感谢。我可以在“符号表 '.symtab' 包含 65 个条目:”下看到一个额外的符号:但我不确定 .symtab 是什么。
  • Executable 和 Linkable Format 定义了可执行二进制文件的结构。它有部分,在这些部分中,有两个部分用于编译器资源管理器生成的可执行文件中的符号。 .symtab 是这两个部分之一的名称。
  • 如果可以发布答案,这非常有帮助。它对其他一些读者也很有用。

标签: c++ static symbols


【解决方案1】:

它改善了链接时间并减少了链接时的内存使用量。

即使对于给定的实现而言这是正确的,但从纯语言的角度来看,未命名命名空间中的静态函数是多余的,并且可以说是一种反模式,可能会使其他开发人员感到困惑;谁可能已经在为 C++ 重载 static链接和完全正交的存储持续时间方面的含义而苦恼。

// .cpp
namespace top {

       int a{};  // external linkage, static storage duration
const  int b{};  // internal linkage, static storage duration
static int c{};  // internal linkage, static storage duration

namespace {

       int d{};  // internal linkage, static storage duration
const  int e{};  // internal linkage, static storage duration
static int f{};  // internal linkage, static storage duration
// ^^^ static is redundant (-> and may confuse devs)

       int g() {}  // internal linkage
static int h() {}  // internal linkage
// ^^^ static is redundant (-> and may confuse devs)

}  // namespace

       int k() {}  // external linkage
static int l() {}  // internal linkage

}  // namespace top

[...] 除了另一个 S.O 问题的最不赞成的答案,它说

通常最好选择静态链接,因为这样不会污染符号表

您引用的答案基于 C++03,其中未命名命名空间中的实体默认没有内部链接。这意味着在 C++03 中,即使未命名命名空间中的实体对其他翻译单元而言可访问(由于未命名命名空间的唯一命名性质),它仍然可以具有外部链接和因此最终出现在符号表中。

从 C++11 起未命名命名空间中的实体具有内部链接。这意味着,从 C++ 语言的角度来看,w.r.t.链接,上面的例子(带有内部链接)是等价的,甚至可以说您的同事混合了这些概念(由于它们的含义过多而很常见),或者您的同事的论点是基于事态的在 C++11 之前。

【讨论】:

    【解决方案2】:

    1 - 在匿名命名空间中使用带有 static 关键字的函数是否有助于减少内存/链接时间?

    就语言而言,静态不会影响匿名命名空间中的函数。这是因为在匿名命名空间中已经实现了与声明函数静态实现的相同的事情。 (请注意,声明一个成员函数 static 具有完全不同的含义)。

    2 - 有没有办法在编译器资源管理器中检查符号表?

    我不知道编译器资源管理器,但您可以使用例如nm 程序来列出符号:http://coliru.stacked-crooked.com/a/0281bc487044ec02

    namespace {
    
           void foo1(){} // internal linkage
    static void foo2(){} // internal linkage
    
    }
    
           void foo3(){} // external linkage
    static void foo4(){} // internal linkage
    

    命令:

    nm main.o | c++filt
    

    输出:

    0000000000000000 T foo3()
    

    【讨论】:

    • 非常感谢,不过我有一个问题。外部链接功能似乎只有一个符号。我可以认为,对于内部链接,永远不会有任何符号。
    • @KadirErdemDemir 当然可以有带有内部链接的函数的符号。将它们排除在外可以被认为是一种优化。如果调用尚未内联扩展的内部函数,则无法优化这些函数。这将是一个本地符号,而不是全局符号。
    • 我还有一个问题。正如@The Philomath 在我的问题的评论部分所建议的那样;我使用了 Godbolt (godbolt.org/z/1nvKhe) 并设法从静态函数“39:0000000000401102 15 FUNC LOCAL DEFAULT 12 ZN12_GLOBAL__N”中找到了一个额外的符号。它显示我是否使用静态。我心中唯一的问题是为什么它没有出现在您的链接中。如果我的可靠与否?
    • @KadirErdemDemir 你没有启用优化器,所以它没有内联函数调用,所以它不能省略本地符号。
    • 所以我认为结论,内部链接的变量/函数总是在符号表中创建一个条目,除非函数被内联,如 Godbolt 示例所示。你同意@eerorika吗?
    猜你喜欢
    • 2011-05-10
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 2019-10-29
    • 2012-11-20
    • 2011-06-04
    • 1970-01-01
    相关资源
    最近更新 更多