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