如果我声明一个内联的大函数,并且编译器选择将其编译为独立函数,那么程序中是否只保证该非内联内联函数的单个副本,或者编译器可能会结束在不同的翻译单元中创建此函数的多个非内联副本?
或者,以一种几乎肯定会引起大量咬牙切齿的方式来改写:在预处理时间不是问题的情况下,在头文件中定义一个内联的大方法是一种有效的方法。能够重用该代码而无需在单独的翻译单元中编译/链接?
答案 0 :(得分:3)
如果我声明一个内联的大函数,并且编译器选择将其编译为独立函数,那么保证程序中只有一个非内联内联函数的副本,
没有。没有这样的保证。 保证的是,只有函数中声明的任何静态变量的单个副本,如果你获取函数的地址,你将始终得到相同的值。
或编译器最终是否会在不同的翻译单元中创建此函数的多个非内联副本?
可能。它们甚至可能不相同:如果它可以看到参数在一个转换单元中始终为null,则它可以省略if (arg != nullptr
)的代码...`。
答案 1 :(得分:3)
你需要在这里非常具体,因为你要求保证。 C ++标准保证程序行为,而不是实现,即使这样也不是为了防止恶意编译器。许多实现细节受到行为的有效约束。但不完全。
编译器可以自由地嵌入您的可执行文件2 ^ 17个不同的任何函数副本,内联与否。这没有意义,但标准并没有禁止它!必须共享静态变量的值和地址,因为这是可观察的,并且如果C ++代码可以获得它们,则每个函数的所有函数指针必须比较相等(它们可以具有地址的不同二进制表示,只是改变做==
的意思!)。
这会发生吗?不,但你要求保证。 C ++标准为实现者留下了巨大的空间。实施质量意味着现代编译器不会经常做愚蠢的事情。
实际上,在使用它的每个.o
文件中创建了一个内联函数。它标记为特殊("弱")。静态链接时,除了其中一个副本之外的所有副本都将被丢弃。保留哪一个将取决于链接顺序,并且可以从构建到构建(特别是部分构建)而变化。只有一个静态本地副本以类似的方式保存。所有指向中的函数或静态局部的指针必须在运行时比较相等。
动态链接导致一些编译器在构建到dll时丢弃它。加载.so
时的其他编译器会查看符号是否已加载,如果是,则不加载.so
中的副本。动态链接的情况是,该函数的多个副本最有可能继续存在并被访问。这种情况没有发生,你很清楚,如果是的话,测试它。 C ++标准没有描述动态链接。
答案 2 :(得分:0)
我建议你仔细阅读以下问题:
"inline" keyword vs "inlining" concept
出于优化目的,如果inline
函数是:
但是,在One Definition Rule (ODR)这两种情况下都可以保证,因为您使用了inline
个关键字。