天天看点

内联函数解读

1.不能有递归

2.不能有静态数据

3.不能包含循环

4.不能包含switch和goto

5.不能包含数组

这是基本原则,

1)表示这个函数嵌套调用自己,多数情况下是不能内联的,

但是有时候,是可以优化成跳转等等情况的,这时候是编译器是可以内联的

2)这种时候容易引出错误,所以这条是必须遵守的。编译器很难在内联的同时,保证语义的正确性。

3)循环有时候,也可以优化成简单指令序列,此时也是可以内联的,

但是一般不提倡 写为内联函数,而不是编译器,一定不能内联

4)switch 多半用地址表,跳转表等方式实现,内联通常不能提高效率

goto 是跳转指令,内联多半也不能提高效率

5)自动数组初始化,很可能包含循环,这样也就没有内联的必要了

首先,内联机制被引入C++作为对宏机制的改进和补充(不是取代)。内联函数的参数传递机制与普通函数相同。但是编译器会在每处调用内联函数的地方将内联函数的内容展开。这样既避免了函数调用的开销又没有宏机制的缺陷。

但是程序代码中的关键字”inline”只是对编译器的建议:被”inline”修饰的函数不一定被内联(但是无”inline”修饰的函数一定不是)。这是因为编译器比绝大多数程序员都更清楚函数调用的开销有多大,所以如果编译器认为调用某函数的开销相对该函数本身的开销而言微不足道或者不足以为之承担代码膨胀的后果则没必要内联该函数。(是否会内联失败请参考此处)

还有一个原因是为了避免编译器陷入无穷递归。如果内联函数之间存在递归调用则可能导致编译器展开内联函数时陷入无穷递归。有时候函数的递归调用十分隐蔽,程序员并不容易发现,所以简单起见,将内联与否的决定权交给编译器。

还有一种不被内联的情况是使用函数指针来调用内联函数。

(inline)内联函数不能为虚函数的原因(virtual)

1.内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的。

2.我们之所以能看到一些象内联函数的虚函数,是因为某个函数是否是内联函数不是由我们说的算,而是由编译器决定的。我们只能向编译器建议,某个函数可以是内联函数(inline关键字),但是编译器有自己的判断法则。所以可能出现这样的情况:

2.1 我们用inline声明的函数却没有inline

2.2 我们没有用inline声明的函数却是inline

2.3 对于inline函数,编译器仍然将它编译成一个有地址的函数

所以,情况比较复杂,从high-level来看的话很难判断函数是否是inline的,如果从low-level来看的话就比较清晰,非内联函数遵从函数调用机制,在汇编中用call来调用。内联函数则没有这些。

继续阅读