1. const常量与宏常量回顾
(1)C++中的const常量可以替代宏常数定义,如:
const int A = 3; ←→ #define A 3
(2)C++中是否有解决方案,可以用来替代宏代码片段呢?
2. 内联函数
2.1 内联函数的定义
(1)C++编译器可以将一个函数进行内联编译,被C++编译器内联编译的函数叫内联函数。
(2)C++中使用inline关键字声明内联函数
inline int func(int a, int b) { return a < b ? a : b; }
(3)内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。(注释:经测试在vs2013下,inline放在声明或定义前均可以)
2.2 内联函数的特点
(1)C++编译器直接将内联函数的函数体插入到函数调用的地方
(2)内联函数没有普通函数调用时的额外开销(压栈、跳转、返回)
(3)C++中推荐使用内联函数替代宏代码片段。
(4)C++编译器也不一定满足函数的内联请求。
【编程实验】内联函数初探 6-1.cpp
#include <stdio.h> #define FUNC(a, b) ((a) < (b) ? (a) : (b)) //MSVC下:要让inline、__forceinline生效必须得做如下的设置: //①在“项目”→“配置属性”→“C / C++” →“优化”→“内联函数扩展”中选择“只适用于__inline(/ Ob1)” //②在“配置属性”→“C / C++” →“所有选项”→“调试信息格式”中选择“程序数据库( / Zi)” inline int func(int a, int b) //VS2013下,inline可放在声明前或也可放在定义前。或两者前都加 { return a < b ? a : b; } int main() { int a = 1; int b = 3; /* int c = FUNC(++a, b);//相当于(++a)<(b)?:(++a):(b); printf("a = %d ", a); //3 printf("b = %d ", b); //3 printf("c = %d ", c); //3 */ int c = func(++a, b); printf("a = %d ", a); //2 printf("b = %d ", b); //3 printf("c = %d ", c); //2 return 0; }
运行结果:
左图:内联函数没嵌入到调用地方(仍为函数调用) 右图:函数体被嵌入到调用的地方
2.3 内联函数与宏的不同
宏代码片段 |
内联函数 |
|
处理方式 |
由预处理器处理,只是进行简单的文本替换 |
由编译器处理,会将函数体嵌入到调用的地方。 但内联请求也可能被编译器拒绝 |
类型检查 |
不做类型检查 |
具有普通函数的特征,会进行参数和返回类型的检查。 |
副作用 |
有 |
无 |
2.4 现代C++编译器对内联函数的优化
(1)现代C++编译器能够进行编译优化,一些函数即没有inline声明,也可能被内联编译。
(2)一些现代的C++编译器提供了扩展语法,可用下列关键字替代inline来对函数进行强制内联,如:
①g++:__atrribute__((always_inline))
②MSVC:__forceinline
(3)MSVC下:要让inline、__forceinline生效必须得做如下的设置:
①在“项目”→“配置属性”→“C/C++” →“优化”→“内联函数扩展”中选择“只适用于__inline(/Ob1)”
②在“配置属性”→“C/C++” →“所有选项”→“调试信息格式”中选择“程序数据库(/Zi)”
【编程实验】内联函数深度示例 6-2.cpp
#include <stdio.h> //MSVC2013下:在函数声明或定义前加inline或__forceinline都可以 //同时,这两个的表现行为几乎一模一样。只不过__forceinline是MS //下的,而inline是标准C++的,可移植性更高。 //__forceinline //__attribute__((always_inline)) //inline int add_inline(int n); int main() { int r = add_inline(10); printf("r = %d ", r); return 0; } __forceinline int add_inline(int n) { int ret = 0; for (int i = 0; i < n; i++) { ret += i; } return ret; }
运行结果:
3. C++中inline内联编译的限制
(1)含有递归调用的函数不能设置为inline
(2)使用了复杂流程控制语句:循环语句和switch语句,无法设置为inline。不能存在过多的条件判断语句(说明:如上述实例,在VS2013下,循环语句是可以被内联的)
(3)函数体不能过于庞大
(4)不能对函数进行取址操作
(5)函数内联声明必须在调用语句之前
4. 小结
(1)C++中可以通过inline声明内联函数
(2)编译器直接将内联函数体扩展到函数调用的地方
(3)inline只是一种请求,编译器不一定允许这种请求
(4)内联函数省去了函数调用时压栈、跳转和返回的开销
(5)const 常量<--->宏常量
内联函数<------>宏代码