我知道关键字inline
具有有用的属性,例如用于在头文件中保留模板特化。
另一方面,我经常读到inline
几乎没有用作编译器实际内联函数的提示。
此外,关键字不能在cpp文件中使用,因为编译器想要在调用时检查用inline
关键字标记的函数。
因此,我对现代编译器的“自动”内联功能(即gcc 4.43)感到有些困惑。当我在cpp中定义一个函数时,编译器是否可以内联它,如果它认为内联对函数有意义,或者我是否剥夺了他的某些优化功能? (这对大多数函数来说都没问题,但对于经常调用的小函数很重要)
答案 0 :(得分:19)
在编译单元中,编译器内联函数没有问题(即使它们没有标记为内联)。在编译单元中,它更难,但现代编译器可以做到。
inline tag
的使用对'现代'编译器几乎没有影响,是否实际内联函数(它具有比人类思维更好的启发式)(除非你指定标志强制它的方式或其他方式(其中)通常是一个坏主意,因为人类做出这个决定是不好的))。
答案 1 :(得分:17)
Microsoft Visual C ++至少从Visual Studio 2005开始就能够这样做。他们称之为“整个程序优化”或“链接时代码生成”。在此实现中,编译器实际上不会生成机器代码,而是将预处理的C ++代码写入目标文件中。然后链接器将所有代码合并到一个巨大的代码单元中并执行实际的编译。
GCC能够做到这一点,因为至少4.5版本,GCC 4.7有重大改进。据我所知,这个功能仍然被认为是有点实验性的(至少在许多不使用它的Linux发行版中)。 GCC的实现非常类似,首先将预处理源(以其GIMPLE中间语言编写)到目标文件中,然后将所有目标文件编译成单个目标文件,然后传递给链接器(这允许GCC继续工作)与现有的连接器。)
许多大型C ++项目也会执行现在被称为“统一构建”的项目。不是将数百个单独的C ++源文件传递到编译器中,而是创建一个包含项目中所有其他源文件的源文件。这背后的最初意图是减少编译时间(因为标题等不必反复解析),但作为副作用,它将具有与上述LTO / LTCG技术相同的结果:给出编译器完全可见所有编译单元中的所有函数。
我在我的C ++编译器(MSVC 2010)的独创性和它的愚蠢之间留下了深刻的印象。一些通过模板进行像素格式转换的代码,在正确内联时已经解析成5-10个汇编指令,变得膨胀成千字节(!)的嵌套函数调用。在其他时候,它如此积极地内联,即使它们包含非平凡的功能,整个类也会消失。
答案 2 :(得分:11)
这取决于您的编译标志。使用-combine
和-fwhole-program
,gcc
将跨越cpp边界执行内联功能。如果您编译成多个目标文件,我不确定链接器会做多少。
答案 3 :(得分:6)
标准规定了如何内联的内容。如果编译器可以访问其实现,则可以内联函数。如果你只有一个包含二进制文件的标题,那就不可能了。如果它在同一个模块中,编译器可以内联函数,即使它在cpp
文件中。