一、 常量与宏回顾
C++中的const常量可以替代宏常数定义,如:
const int A = 3;等价于 #define A 3
那么C++中是否有解决方案替代宏代码片段呢?请看以下内容。
二、 内联函数的定义
(1)C++中推荐使用内联函数替代宏代码片段;
(2)C++中使用inline关键字声明内联函数;
(3)内联函数声明时inline关键字必须和函数定义结合再一起,否则编译器会直接忽略内联请求。内联函数的定义如图1所示:
![d909cb118a469645a6af04ab0247d214.png](https://img-blog.csdnimg.cn/img_convert/d909cb118a469645a6af04ab0247d214.png)
图1
三、 内联函数的特点
(1)C++编译器可以将一个函数进行内联编译,被C++编译器内联编译的函数叫做内联函数;
(2)C++编译器直接将函数体插入函数调用的地方;
(3)内联函数没有普通函数调用时的额外开销(压栈,跳转,返回);
(4)C++编译器不一定满足函数的内联请求;函数的内联请求可能被编译器拒绝;
(5)内联函数具有普通函数的特征(参数检查,返回类型等 );
(6)宏代码片段由预处理器处理,进行简单的文本替换 ,没有任何编译过程,因此可能出现副作用。
如图2所示的代码,用情况1编译后的执行结果如图3所示;这就是宏代码出现的副作用,情况1的文本替换后如图 4所示:
![61b067c91f5cc71cfb9e9e0fde6bd111.png](https://img-blog.csdnimg.cn/img_convert/61b067c91f5cc71cfb9e9e0fde6bd111.png)
图2
![f573d535211ddd2cb1e7bb4b070d13c8.png](https://img-blog.csdnimg.cn/img_convert/f573d535211ddd2cb1e7bb4b070d13c8.png)
图3
![2ff201d7cb1a73129924854c1b6922f3.png](https://img-blog.csdnimg.cn/img_convert/2ff201d7cb1a73129924854c1b6922f3.png)
图4
用图2代码的情况2编译执行后的结果如图5所示,这个就和分析的一样,因此内联函数不会产生副作用。
![c09ef81ea88863da7609f7709cde6c6f.png](https://img-blog.csdnimg.cn/img_convert/c09ef81ea88863da7609f7709cde6c6f.png)
图5
用图2代码的情况2在VS2015的默认编译后的汇编代码如图6所示;从图6中可以看到有函数的调用,说明inline的内联请求被拒绝了;这是因为编译器的优化功能没有被设置。编译器的优化功能设置如图7所示,经过设置了编译器的优化功能后,编译后的汇编代码如图8所示,从图8中可以到没有函数调用了,而是将函数体插入函数调用的地方。
![8b16dd9d3dff0d5614ba06c7afdbacfd.png](https://img-blog.csdnimg.cn/img_convert/8b16dd9d3dff0d5614ba06c7afdbacfd.png)
图6
![787b9d354f93096fbad965e87f4b2233.png](https://img-blog.csdnimg.cn/img_convert/787b9d354f93096fbad965e87f4b2233.png)
图7
![db9f85202887027f90f10da4dd508904.png](https://img-blog.csdnimg.cn/img_convert/db9f85202887027f90f10da4dd508904.png)
图8
四、 现代C++编译器对内联函数的优化
(1)现代C++编译器能够进行编译优化 ,一些函数即使没有inline声明,也可能被内联编译。
(2)一些现代C++编译器提供了扩展语法,能够对函数进行强制内联,如图9的代码和如下所示:
a) g++:__attribute__((always_inline))属性
b) MSVC:__forceinline
![e0cbffa917d8951e5bdb3d6666b324ec.png](https://img-blog.csdnimg.cn/img_convert/e0cbffa917d8951e5bdb3d6666b324ec.png)
图9
五、 C++中inline内联编译的限制
(1)不能存在任何形式的循环语句;
(2)不能存在过多的条件判断 语句;
(3)函数体不能过于庞大;
(4)不能对函数进行取地址操作;
(5)函数内联声明必须在调用语句之前。
六、 内联函数、宏和带参数函数三者的比较
内联函数的优点:函数代码被装入符号表中,在使用时进行替换没有调用开销,效率高,会进行参数类型检查。
内联函数的缺点:函数代码较长,使用内联将消耗过多内存;
函数体内有循环,执行代码的时间比较长。
宏的优点:原地展开,没有调用开销;
并且在预处理阶段完成,不占用编译时间。
宏的缺点:不进行类型检查,多次宏替换会导致代码体积变大;
一些参数的副作用会导致得出错误的结果。
带参函数的优点:编译器会做参数的静态类型检查。
带参函数的缺点:需要传参、栈变量的开辟和销毁;
压栈、跳转、返回开销;