当程序执行函数调用后,系统要为被调函数建立栈空间,记录、维护程序当前运行情况(保护现场),传递参数以及控制程序执行的转移等等。
上图中,add函数只被调用了一次,其栈帧也只开辟和回收了一次,所以对程序运行速率影响不大。但若是同add函数般代码量小、简单的函数在程序中反复被调用,就需要反复为add函数进行开辟、回收栈帧等操作,这就使得简单程序运行速率大幅下降,不如把该函数的代码直接嵌入到调用该函数的程序中:(例子较为简单,但能体现实际情况)
但是这样有缺点,一是相同代码重复书写,二是程序可读性没有使用函数的好。
为了协调较简单函数的调用效率与程序可读性,C++提供了另一种方法,即定义内联函数,方法是在定义函数时使用修饰词 inline 。
inline int add(int a, int b) {
int c = a + b;
return c;
}
被修饰为内联函数的函数,在程序编译期间,编译器会在函数调用点内联展开该函数。
实例:
在debug模式下,设置编译器。编译器在进行如下设置后,适用于inline函数展开。
此时,再对普通函数调用与inline函数展开,分别查看反编译分析。
普通函数调用会在编译时转换成 call 命令(函数调用);内联函数在编译时在程序对应位置进行了展开。此时,内联函数使用就更高效。
重点:
1、inline是一种以空间换时间的做法,省去函数调用的额外开销。但是当函数体的代码过长或者是递归函数(递归函数无法展开)时,即便加上inline关键字,也不会在调用点以内联展开该函数。inline对于编译器只是一个建议,编译器会根据实际情况自动优化。
2、如果函数执行开销小于开栈和清栈开销(函数体较小),使用inline函数效率高;如果函数执行开销大,开栈清栈开销可忽略,则使用普通函数方式处理。
3、inline不建议声明与定义分离(将声明放入.h头文件中,定义放入.cpp文件中),分离会导致链接错误。因为inline 函数被展开了,函数名消失了,就没有函数地址了,链接就找不到。
4、内联函数与宏定义的区别:
使用宏定义也可以达到一定程度上的函数替换,并且带有泛性:
(1)内联函数在编译时展开;带参的宏在预编译时展开。
(2)内联函数直接嵌入到目标代码中;带参的宏只是做简单的文本替换。
(3)内联函数有类型检测、语法判断等功能;宏只进行替换。