C++内联函数
什么是内联函数
以
inline
修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
为什么存在内联函数
我们知道,普通的函数需要建立栈帧空间
因此,可以利用宏来定义一些小的函数(行数较少的)
这样,函数调用的时候其实就是语句的直接替换,而不存在函数栈帧的创建和销毁
比如,一个实现两个数相加的函数
//普通函数
int Add(int x,int y)
{
return x+y;
}
//宏函数形式
#define ADD(a,b) ((a)+(b))
对比于普通函数来说,宏的优点就很明显了
- 使用宏函数,可以不用建立栈帧,减小系统开销,提高运行效率
但是显然,宏也有缺点
- 相比于函数,宏定义的函数可读性差,函数体复杂
- 宏函数参数没有类型检查,容易出现bug(如不同类型的相加)
- 宏在预处理阶段就直接整体替换展开了,不方便调试
所以,为什么存在内联函数?
内联函数的存在就是为了解决宏的缺点,同时保留宏的优点
内联函数的查看
既然你说,内联函数不会调用函数,直接展开
有什么证据呢?
如图所示,这是没有加inline
修饰的函数
可以看到反汇编中存在call Add
这条命令,也就是会调用函数
但是如果加了inline
修饰呢?
注意
- 如果在release模式下,查看汇编代码中是否存在call Add即可
- 但是如果在debug模式,需要进行设置,因为
inline
属于一种优化,debug模式下为了方便调试默认不会进行优化
以VS2019为例,关闭优化:
可以看到,关闭优化之后,执行到Add函数的时候,并没有执行优化
说明inline
是存在的
内联的注意事项
-
inline
是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用缺陷:可能会使目标文件变大
优势:少了调用开销,提高程序运行效率
-
inline
对于编译器只是一个建议,不同编译器关于inline实现机制可能不同一般函数规模较小(展开汇编 小于10行),没有递归。并且会频繁调用的函数,编译器会采纳
inline
的建议。否则编译器会忽略inline
的建议。因为如果展开汇编代码很多的话,会导致程序的大小变大!比如:
如果一个函数有100行,调用10000次 比较程序的语句数量 不展开:10000个call + 100 个指令 展开:100*10000 条指令 可执行程序会明显变大
而可执行程序变大的结果就是:
比如更新《王者荣耀》这个游戏,500MB的更新内容硬是要更新2个G,难受不难受😫
如《C++primer》中所述
inline
的声明和定义不要分离,如果在.h中声明inline func()
,然后在test.cpp
中进行定义,main.cpp
中进行调用。那么当调用的时候,因为有头文件所以编译可以通过.但是链接的时候,就去test.cpp
生成的目标文件的符号表中去找函数的地址(call动作),但是由于func()
是inline
修饰的,所以编译器并不会把函数的地址放入符号表,所以就会出现链接错误
如果函数用inline
属性修饰,那么编译器统一不会把该函数的信息放到符号表
所以内联函数一般是在.h中直接定义的,或者在需要调用的本.cpp
文件中定义