有些人喜欢使用inline
关键字C
,并在标题中添加大功能.你什么时候认为这是无效的?我认为它有时甚至很烦人,因为它很不寻常.
我的原则是inline
应该用于非常频繁访问的小函数,或者用于实际类型检查.无论如何,我的品味指导我,但我不知道如何最好地解释为什么inline
对大功能不那么有用的原因.
在这个问题中,人们建议编译器可以更好地猜测正确的事情.这也是我的假设.当我尝试使用这个参数时,人们回复它不适用于来自不同对象的函数.好吧,我不知道(例如,使用GCC).
谢谢你的回答!
inline
做两件事:
为您提供"一个定义规则"的豁免(见下文).这始终适用.
为编译器提供一个提示以避免函数调用.编译器可以自由地忽略它.
#1可能非常有用(例如,如果短,则将标题放在标题中),即使#2被禁用也是如此.
在实践中,编译器通常会更好地确定自己内联的内容(特别是如果可以使用配置文件引导优化).
[编辑:完整参考文献和相关文字]
以上两点均遵循ISO/ANSI标准(ISO/IEC 9899:1999(E),通常称为"C99").
在§6.9"外部定义"中,第5段:
一个外部定义为外部声明,这也是一个功能(比内联定义其他)或对象的定义.如果在表达式中使用通过外部链接声明的标识符(而不是作为sizeof运算符的操作数的一部分,其结果是整数常量),则整个程序中的某个地方应该只有一个标识符的外部定义; 否则,不得超过一个.
虽然C++中的等价定义明确地命名为单定义规则(ODR),但它具有相同的用途.外部(即不是"静态",因此对于单个翻译单元本地 - 通常是单个源文件)只能定义一次,除非它是函数和内联.
在§6.7.4,"函数说明符"中,定义了内联关键字:
使函数成为内联函数表明对函数的调用尽可能快.[118]这些建议有效的程度是实施定义的.
脚注(非规范性),但提供了澄清:
例如,通过使用通常的函数调用机制的替代方法,例如"内联替换".内联替换不是文本替换,也不是创建新函数.因此,例如,在函数体内使用的宏的扩展使用它在函数体出现时的定义,而不是调用函数的位置; 和标识符指的是身体发生范围内的声明.同样,该函数具有单个地址,而不管除外部定义之外还发生的内联定义的数量.
简介:C和C++的大多数用户对内联的期望并不是他们得到的.其明显的主要目的是避免功能调用开销,这是完全可选的.但是为了允许单独编译,需要放宽单一定义.
(所有重点都在标准的引用中.)
编辑2:几点说明:
外部内联功能有各种限制.您不能在函数中使用静态变量,也不能引用静态TU范围对象/函数.
刚刚在VC++的" 整个程序优化 "中看到了这一点,这是编译器执行自己的内联事务而非作者的一个例子.
内联声明的重要之处在于它不一定做任何事情.在许多情况下,编译器可以自由决定内联未声明的函数,并链接内联声明的函数.
一个例子来说明内联的好处.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.
当你没有内联编译时,编译器不会优化循环,输出.asm将显示以下内容:
;*----------------------------------------------------------------------------* ;* SOFTWARE PIPELINE INFORMATION ;* Disqualified loop: Loop contains a call ;*----------------------------------------------------------------------------*
当您使用内联进行编译时,编译器会了解循环中发生的情况并进行优化,因为它确切地知道发生了什么.
输出.asm将具有优化的"流水线"循环(即它将尝试充分利用所有处理器的ALU并尝试保持处理器的流水线完整而没有NOPS).
在这个特定的情况下,我能够将我的表现提高大约2倍或4倍,这使我在实际截止日期之前得到了我所需要的.
ps我正在研究定点处理器...而像sin/cos这样的任何浮点运算都会影响我的性能.
对于大型函数,不应该使用内联的另一个原因是库的情况.每次更改内联函数时,您可能会失去ABI兼容性,因为针对旧标头编译的应用程序仍然内联旧函数版本.如果将内联函数用作类型安全宏,那么在库的生命周期中永远不需要更改函数的可能性很大.但是对于大功能而言,这很难保证.
当然,只有当函数是您的公共API的一部分时,此参数才适用.