为什么没有模板函数比模板函数生成更多的二进制文件

3
看看这个简单的程序。
#include <cstdio>
#include <cstdlib>

void foo(){ printf("%d",1); }
int main(){ foo(); }

我在Linux上使用gcc 4.6.4编译它,命令为-std=c++0x -O2 -g -Wall。生成的二进制文件大小为11,238字节。

然而,这段代码只占用了11,150字节:

#include <cstdio>
#include <cstdlib>

template< bool = false> void foo(){ printf("%d",1); }
int main(){ foo(); }

我也使用clang 3.3进行了测试,结果分别为5684字节和5636字节。

为什么没有模板版本的函数要生成更多的二进制代码?


这是7,168字节,在Visual Studio 2013中也是7,168字节(默认模板值版本无法编译,我不得不明确提供它)。 - Spook
我会使用 VS 2014 :) - Khurshid Normuradov
显然,内联版本应该占用更少的空间(在这种情况下没有函数调用/参数传递)。你尝试过将非模板版本设置为“inline”吗? - user396672
3个回答

3

这只是一个猜测:

在第一个例子中,foo 具有外部链接并且不是内联的。编译器可能会生成一个非内联版本以防其他翻译单元使用它;链接器可能不会将其删除,导致它在可执行文件中占用空间。

在第二个例子中,foo 是一个模板,因此链接器更有可能能够将其排除在外(因为当模板在多个翻译单元中实例化时,需要处理多个定义)。

您必须检查二进制文件才能确定发生了什么。如果您将第一个声明为 staticinline,可能会看到差异。


在第二个版本中,foo不是内联的。它是一个模板,因此编译器知道其他翻译单元也会看到源代码(与第一种情况不同)。当然,在任何一种情况下都将foo内联是编译器非常值得怀疑的决定。除非它正在分析main函数,从中可以得出结论没有其他的翻译单元。 - James Kanze
@JamesKanze:你说得对;由于某种原因,我认为函数模板是隐式内联的(而不仅仅是在多个定义方面表现得像内联函数),并且过于简化了我的语言。 - Mike Seymour

2
我认为这里没有通用的答案;这很大程度上取决于编译器的实现。
此外,差异非常小,所以很难确定这是否是正确的结论。
你应该阅读生成的代码;也许那能给你一些线索,告诉你字节从哪儿被删减了。
如果在非模板版本中使 foo() 成为 static,是否有帮助?也许它在一个情况下被内联,而在另一个情况下没有,等等。

使用 static 关键字后,gcc 的版本 1-11098 和 2-11146 都会生成更多的二进制代码。而 clang 的版本 1-5636 和 2-5584 也是如此。也就是说,在添加了 static 后,模板版本会生成更多的二进制代码 :) - Khurshid Normuradov

0

输出的二进制代码取决于编译器的实现。在编译期间,它将生成符号表,这取决于函数名称。模板函数会被翻译成较长的符号名称,从而增加了二进制文件的大小。

您可以通过简单地将函数名称从foo更改为foo1来查看这一点,这将使二进制文件增加一个字节。

在剥离符号之后,二进制文件的大小相同

-rwxr-xr-x 1 dejovivl dejovivl 6288 Nov  5 13:00 a.out*
-rwxr-xr-x 1 dejovivl dejovivl 6288 Nov  5 13:01 a.out*

要去掉符号,请使用 strip :

strip a.out

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接