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