现代c++编译器能否内联在cpp文件中定义的函数

Can modern C++ compilers inline functions that are defined in a cpp file

本文关键字:文件 cpp 定义 函数 编译器 c++ 现代      更新时间:2023-10-16

我知道关键字inline具有有用的属性,例如在头文件中保持模板专门化。另一方面,我经常读到,inline几乎是无用的提示,为编译器实际上内联函数。此外,该关键字不能在cpp文件中使用,因为编译器希望在调用标记有inline关键字的函数时检查它们。

因此,我对现代编译器(即gcc 4.43)的"自动"内联功能有点困惑。当我在cpp中定义一个函数时,如果编译器认为内联对函数有意义,那么它是否可以内联它,或者我是否剥夺了他的一些优化能力?(这对于大多数函数来说是可以的,但对于经常调用的小函数来说,重要的是要知道)

在编译单元内,编译器不会有内联函数的问题(即使它们没有被标记为内联)。跨编译单元更难,但现代编译器可以做到。

使用inline tag对'现代'编译器以及它是否实际上内联函数(它具有比人类思维更好的启发式)几乎没有影响(除非您指定标志以某种方式强制它(这通常是一个坏主意,因为人类不擅长做出这个决定))。

至少从Visual Studio 2005开始,Microsoft Visual c++就能够做到这一点。他们称之为"整个程序优化"或"链接时间代码生成"。在此实现中,编译器实际上不会生成机器码,而是将预处理的c++代码写入目标文件中。然后链接器将所有的代码合并到一个巨大的代码单元中,并执行实际的编译。

GCC至少从4.5版开始就能做到这一点,在GCC 4.7中将有重大改进。据我所知,这个特性仍然被认为是实验性的(至少到目前为止,许多Linux发行版还没有使用它)。GCC的实现方式非常相似,首先将预处理的源代码(用其GIMPLE中间语言)写入目标文件,然后将所有目标文件编译成单个目标文件,然后将其传递给链接器(这允许GCC继续使用现有的链接器)。

许多大型c++项目也做现在被称为"统一构建"的事情。不需要将数百个单独的c++源文件传递到编译器中,而是创建一个源文件,其中包含项目中所有其他源文件。这样做的初衷是为了减少编译时间(因为头文件等不需要一遍又一遍地解析),但作为副作用,它会产生与上面提到的LTO/LTCG技术相同的结果:让编译器完美地看到所有编译单元中的所有函数。


我对我的c++编译器(MSVC 2010)的独创性和它的愚蠢印象深刻。一些通过模板进行像素格式转换的代码,在适当内联时可以分解为5-10个汇编指令,但却膨胀成数千字节(!)的嵌套函数调用。在其他时候,它如此积极地内联,以至于整个类消失,即使它们包含重要的功能。

这取决于您的编译标志。对于-combine-fwhole-program, gcc将跨cpp边界进行函数内联。如果你编译成多个目标文件,我不确定链接器会做多少。

标准没有规定函数如何内联。如果编译器可以访问函数的实现,它们可以内联函数。如果你只有一个二进制文件的头文件,这是不可能的。如果它在同一个模块中,编译器可以内联函数,即使它在cpp文件中。