制作一个自由的静态函数有什么好处吗?

Are there any advantages to making a free static function?

提问人:Luchian Grigore 提问时间:9/30/2011 最后编辑:Luchian Grigore 更新时间:9/30/2011 访问量:13551

问:

我有一个文件,其中包含一些静态免费功能。我知道这在头文件中有什么帮助,但是由于 cpp 不在任何地方,有什么意义呢?它有什么好处吗?.cpp

C++语言

评论

9赞 Griwes 9/30/2011
你能更清楚地问这个问题吗?
0赞 Luchian Grigore 9/30/2011
你没有得到哪一部分?另外,为什么要投反对票?
0赞 Griwes 9/30/2011
反对票不是来自我。至于你的第一个问题:阅读你的原始帖子并尝试理解它。看来你失去了一些角色......
4赞 PlasmaHH 9/30/2011
有不同的b吗?是的,有。B.
1赞 Luchian Grigore 9/30/2011
右。。。一定是错误地删除了其余的问题。现在我不记得我还想问什么:D

答:

84赞 Kerrek SB 9/30/2011 #1

将自由函数声明为 会给它们提供内部链接,这允许编译器进行更积极的优化,因为现在可以保证 TU 之外的任何人都看不到该函数。例如,该函数可能会从程序集中完全消失,并在所有位置内联,因为不需要提供可链接的版本。static

当然,请注意,这也略微改变了语义,因为允许在不同的 TU 中拥有同名的不同静态函数,而对非静态函数进行多个定义是错误的。

评论

0赞 Luchian Grigore 9/30/2011
谢谢,这是我所希望的一种答案。
5赞 Steve Jessop 9/30/2011
“允许在不同的 TU 中拥有同名的不同静态函数”——如果您喜欢大括号和额外的缩进,无名称命名空间也可以提供这种效果;
1赞 Kerrek SB 11/2/2013
@SteveJessop:这是真的(我们不缩进命名空间:-)),但是这是在 C++11 中添加的吗?我的意思是,内部联系。
2赞 Steve Jessop 11/2/2013
是的,无名称命名空间具有内部链接这一事实对 C++11 来说是新的。
0赞 Timmmm 5/16/2014
编译器肯定可以做到这一切吗?这个关键字在现代编译器中基本上被忽略了——“Clang 将其视为程序员的温和建议”,因此它不会更改内联,并且链接器可以删除未使用的函数。inline
10赞 3 revsJohannes Schaub - litb #2

由于评论框太小,无法解释为什么你的推理有严重的错误,我把这个作为社区维基的答案。对于仅标头函数,几乎毫无用处,因为任何包含其标头的人都将获得不同的函数。这意味着您将复制编译器为每个函数创建的代码(除非链接器可以合并代码,但据我所知,这不太可能),更糟糕的是,如果函数具有局部静态,则每个局部变量都将不同,从而导致每次调用来自不同包含的定义时都可能进行多次初始化。不好。static

仅标头函数需要的是 (non- ),这意味着每个标头包含将定义相同的函数,并且现代链接器能够不像 done for 那样复制每个定义的代码(在许多情况下,C++ 标准甚至要求它们这样做),而是从所有包含创建的所有定义中只发出一个代码副本。inlinestaticinlinestatic

评论

1赞 Steve Jessop 9/30/2011
我认为你夸大了制作函数在多大程度上防止了代码重复。标记它不会阻止编译器实际内联它,从而复制代码的很大一部分(如果不是 prolog 等)。但它确实避免了可能出现的情况,即即使在给定自由支配的情况下,编译器也会选择不内联它。inlineinlinestatic
0赞 Johannes Schaub - litb 9/30/2011
@Steve 我不是在说关于内联对函数的调用。标准 C++ 中没有任何关键字可以阻止对函数的内联调用,无论是对函数还是对函数的调用。这是编译器的业务,它将根据需要内联调用和函数。inlinestaticstaticinline
0赞 Steve Jessop 9/30/2011
你说过,“现代链接器不会复制每个定义的代码”。鉴于内联的存在,我认为这种说法具有误导性。也许更准确的是,“现代链接器能够不复制代码”。
1赞 Johannes Schaub - litb 9/30/2011
@Steve你对误导因素的看法是正确的。但是,该标准甚至要求链接器不要复制其代码,如果您获取其函数的地址并打印/跨 TU 进行比较。出于这个原因,为内联函数生成的 afaik 代码被放入专门命名的部分中,以便链接器可以很容易地丢弃除单个代码副本之外的所有代码。对于函数,没有这样的事情。为什么编译器会选择说“啊,我想要代码膨胀,所以我把这个内联函数放进去,所以它不能被合并!static.text
1赞 Johannes Schaub - litb 9/30/2011
@Steve一点也不:)A 在不同的 TU 中具有不同的地址(因为定义具有内部链接,因此定义了不同的功能),非静态在不同的 TU 中具有相同的地址(因为定义具有外部链接,因此定义了相同的功能)。如果它们有一个局部静态变量,则在第一种情况下会得到多个对象,而在第二种情况下,你会得到一个对象和该对象的初始化。static inlineinline
0赞 David Hammen 9/30/2011 #3

有点不合时宜的响应,因为解决的第一个项目在我的脑海中引发了一些巨大的问题。

但是由于 CPP 不包括在任何地方

我强烈希望你永远不要在任何地方出现源文件。预处理器不关心源与标头之间的区别。这种区别的存在很大程度上是为了造福人类,而不是造福于编译者。有很多原因,你不应该在任何地方使用源文件。#include#include

我有一个 .cpp 文件,其中包含一些静态免费功能。我知道这对头文件有什么帮助......

那会有什么帮助?

如果非静态自由函数具有外部链接,则在标头中声明这些自由函数。在标头中声明(但不定义)静态自由函数无济于事。这是一个障碍。你想把东西放在一个标题中,帮助你和其他程序员理解某些东西的导出内容。这些静态自由函数不是导出的内容。您可以在标头中定义自由函数,从而使它们成为导出的内容,但标准做法是使用 关键字而不是 .inlinestatic

就源文件中的静态自由函数而言,您可能需要考虑将这些函数的声明放在源文件顶部附近(但不要放在标头中)。这有助于提高可理解性。如果没有这些声明,源文件的组织将看起来是 Pascalish,首先定义低级函数。大多数人喜欢自上而下的演示。通过首先声明函数,您可以采用自上而下的策略。或者由内而外的策略,或者任何使功能最容易理解的策略。

评论

0赞 DeltA 11/16/2022
“大多数人都喜欢自上而下的演示”。我不同意,但这只是我个人的看法。你有实际的统计数据来证明这个说法吗?