代码之家  ›  专栏  ›  技术社区  ›  elmarco

什么时候“内联”无效?(C)中

  •  15
  • elmarco  · 技术社区  · 17 年前

    inline 关键词 C ,并在

    我的原则是 内联 应用于经常访问的小函数,或用于进行实类型检查。无论如何,我的品味引导着我,但我不知道如何最好地解释为什么 内联 对于大型函数来说,它不是那么有用。

    this question 人们建议编译器可以更好地猜测正确的操作。这也是我的假设。当我尝试使用这个参数时,人们回答说它不适用于来自不同对象的函数。嗯,我不知道(例如,使用GCC)。

    谢谢你的回答!

    12 回复  |  直到 9 年前
        1
  •  26
  •   Richard    14 年前

    inline 做两件事:

    1. 允许您免于遵守“一个定义规则”(见下文)。这 应用。
    2. 给编译器一个避免函数调用的提示。编译器可以随意忽略这一点。

    #即使禁用了#2,1也可能非常有用(例如,如果短,则将定义放在标题中)。

    在实践中,编译器通常能够更好地确定自己内联的内容(特别是在配置文件引导优化可用的情况下)。


    [编辑:完整参考资料和相关文本]

    以上两点均遵循ISO/ANSI标准(ISO/IEC 9899:1999(E),通常称为“C99”)。

    一 外部定义

    虽然C++中的等值定义被明确地命名为一个定义规则(ODR),但它的作用是相同的。外部(即不是“静态的”,因此是单个翻译单元(通常是单个源文件)的本地)只能定义一次 除非 这是一个函数 和

    在§6.7.4“函数说明符”中,内联关键字定义如下:

    尽可能快。 [118] 这些建议的有效程度是:

    和脚注(非规范性),但提供了澄清:

    例如,通过使用常规函数调用机制的替代方法,如内联替换。内联替换不是文本替换,也不会创建新函数。因此,例如,函数体中使用的宏的扩展使用它在函数体出现时的定义,而不是在调用函数时的定义;标识符是指主体所在范围内的声明。同样,该函数只有一个地址,而不管除了外部定义之外还有多少内联定义。

    大多数C和C++用户从内联中得到的不是他们得到的。其明显的主要目的是避免函数调用开销,这是完全可选的。但为了允许单独编译,需要放宽单一定义。

    (标准中引用的所有重点。)


    编辑2:一些注释:

    • 对外部内联函数有各种限制。函数中不能有静态变量,也不能引用静态TU范围对象/函数。
    • 刚刚在VC++上看到这个“ whole program optimisation ,这是一个编译器执行自己的内联操作的示例,而不是作者。
        2
  •  5
  •   SingleNegationElimination    17 年前

        3
  •  5
  •   quinmars    17 年前

    对于大型函数,不应使用内联的另一个原因是库。每次更改内联函数时,可能会失去ABI兼容性,因为根据旧头编译的应用程序仍然内联了旧版本的函数。如果内联函数被用作类型安全宏,那么在库的生命周期中,函数永远不需要更改的可能性很大。但对于大型功能来说,这很难保证。

    当然,只有当函数是公共API的一部分时,此参数才适用。

        4
  •  5
  •   Trevor Boyd Smith knh170    17 年前

    一个例子来说明内联的好处。sinCos.h:

    int16 sinLUT[ TWO_PI ]; 
    
    static inline int16_t cos_LUT( int16_t x ) {
        return sin_LUT( x + PI_OVER_TWO )
    }
    
    static inline int16_t sin_LUT( int16_t x ) {
        return sinLUT[(uint16_t)x];
    }
    

    当执行一些繁重的数字运算时,为了避免在计算sin/cos上浪费周期,您可以用LUT替换sin/cos。

    当您编译时没有内联编译器 不会优化循环

    ;*----------------------------------------------------------------------------*
    ;*   SOFTWARE PIPELINE INFORMATION
    ;*      Disqualified loop: Loop contains a call
    ;*----------------------------------------------------------------------------*
    

    当您使用内联编译时,编译器知道循环中发生了什么,并将进行优化,因为它确切地知道发生了什么。


    在这个特定的案例中,我能够将性能提高约2倍或4倍,这使我在实时截止日期所需的时间内完成任务。


    p、 我在一个定点处理器上工作。。。任何像sin/cos这样的浮点运算都会破坏我的性能。

        5
  •  4
  •   Xolve    17 年前

    使用指向函数的指针时,内联无效。

        6
  •  3
  •   Ken    17 年前

    内联在一种情况下是有效的:当您遇到性能问题时,使用真实数据运行探查器,发现一些小函数的函数调用开销非常大。

    除此之外,我无法想象你为什么要用它。

        7
  •  2
  •   Diego Sevilla    17 年前

        8
  •  2
  •   Christoph    17 年前

    我主要使用内联函数作为类型安全宏。在相当长的一段时间里,人们一直在谈论向GCC添加对链接时间优化的支持,特别是自从LLVM出现以来。不过,我不知道实际实施了多少。

        9
  •  2
  •   T.E.D.    17 年前

    我个人认为你不应该 曾经 内联,除非您首先在代码上运行探查器,并且已经证明该例程上存在可以通过内联部分缓解的重大瓶颈。

    这是Knuth警告过的又一个过早优化案例。

        10
  •  2
  •   chappar    17 年前

    内联可用于小型且常用的函数,如getter或setter方法。对于大型函数,不建议使用内联,因为它会增加exe大小。

        11
  •  1
  •   dirkgently    17 年前
    1. inline 仅作为提示。
    2. 只是最近才加的。因此,仅适用于最新的符合标准的编译器。
        12
  •  1
  •   Tim Post Samir J M Araujo    17 年前

    内联函数应该大约为10行或更少,根据您选择的编译器而定。

    做 内联函数,如果不是,为什么不是?许多编译器只是默默地说“去你的!”在这方面。

    因此,如果:

    静态内联无符号整数foo(常量字符*bar)

    .. 与静态int foo()相比,这并不能改善问题。现在是时候重新审视优化(以及可能的循环)或与编译器争论了。首先要特别注意与编译器争论,而不是与开发编译器的人争论。。或者,当你第二天打开你的收件箱时,你正在等待大量不愉快的阅读。

    同时,当把某件事(或试图把某件事)内联起来时,这样做是否真的证明了膨胀的合理性?你真的想扩展这个功能吗 每一个