【问题标题】:Can modern C++ compilers inline functions that are defined in a cpp file现代 C++ 编译器可以内联 cpp 文件中定义的函数吗
【发布时间】:2012-01-17 00:19:21
【问题描述】:

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

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

【问题讨论】:

  • 你应该检查你的编译器的链接时优化支持。在 GCC 中,这是通过 -flto 启用的。
  • 非常感谢所有的答案。由于它们相似,我选择了最快的一个作为接受,而这三个都教会了我一些东西。
  • 我们不希望鼓励快速回答。人们已经有太多的比赛需要快速输入常见的(但不正确的信息)来获得支持。我们希望鼓励深思熟虑和信息丰富的答案。注意:请注意,我不同意您的最终选择,只是它的派生方法。
  • @Loki:我完全同意你的观点,这场比赛是问答中的常见瘟疫。也许我应该再补充一个理由。如果内容有效并且满足我的回答,我倾向于接受代表最低的人的回答。我认为这有助于人们建立一些声誉,鼓励参与并导致门户网站更加多样化。当然,这仅适用于好的答案。
  • 澄清一下:你的意思是内联文件吗? “在 cpp 文件中定义”是指“不在共享 hpp 中”吗?

标签: c++ compiler-construction inline


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • +1,但我不同意inline tag has little affect。据我所知,即使是最新添加的 MSVC 也会内联所有标记为此类的函数,(然后在内存不足时崩溃。万岁!)
    • @MooingDuck: From: msdn.microsoft.com/en-us/library/z8y1yy88%28v=vs.71%29.aspx 插入(称为内联扩展或内联)只有在编译器的成本/收益分析表明它是有利可图的情况下才会发生。 。内联用户标记为内联的所有内容将非常愚蠢。众所周知,人类是糟糕的程序员,对系统的许多部分几乎没有真正的了解(我们的机器霸主万岁)。
    • @LokiAstari: connect.microsoft.com/VisualStudio/feedback/details/699728/…: 证明 MSVC 会内联某些函数,甚至会耗尽内存。 GCC 编译并运行它就好了。
    • 这只是表明 MS 编译器在其启发式方法上过于激进,而 gcc 则更胆小。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      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 条汇编指令,但会膨胀成千字节(!)的嵌套函数调用。在其他时候,它的内联非常激进,以至于整个类都消失了,即使它们包含不平凡的功能。

      【讨论】:

        猜你喜欢
        • 2011-06-19
        • 1970-01-01
        • 2011-04-28
        • 2011-10-30
        • 2021-11-17
        • 2014-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多