1. 内联函数
1.1 内联函数的定义
- 内联函数:指用inline关键字修饰的函数;
- 内联函数:在类内定义的函数被默认成内联函数;
- 内联函数:不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处,编译时,类似宏替换,使用函数体替换调用处的函数名;
- 内联函数的作用:内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数。 一个小内存空间的函数非常受益。
注:一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。影响性能的一个重要因素是内联技巧。
1.2 内联函数的使用注意
- 递归函数不能定义为内联函数;
- 内联函数一般适合于不存在while和switch等复杂的结构,而且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数;
- 内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数;
- 对内联函数不能进行异常的接口声明;
1.3 内联函数与宏比较
- 内联函数的功能和预处理宏的功能相似。
- 宏的优缺点:
优点:宏只是在预处理的地方把代码展开,不需要额外的空间和时间方面的开销,所以调用一个宏比调用一个函数更有效率;
缺点:宏不能访问对象的私有成员,宏的定义很容易产生二义性; - 内联函数与宏的区别:
宏是由预处理器对宏进行替代。
内联函数是通过编译器控制来实现的;
内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销;
1.4 内联函数的性能测试
可以做一个实验,让主函数分别调用内联函数和非内联函数,由于调用一次函数的开销实在太小,只有几个机器指令,甚至还有机器硬件专设的机构帮忙,所以,为了看清内联函数与非内联函数的差别,可以分布调用10亿次函数来放大时间差。
#include <iostream> #include <time.h> using namespace std; class A { public: int calc1(int a, int b); }; int A::calc1(int a, int b) { return a+b; } class B { public: inline int calc2(int a, int b)//或 int calc2(int a, int b) { return a+b; } }; int main() { A a; B b; int x[1000], y[1000], z[1000]; clock_t t = clock(); for(int i=0; i<1000; i++) { for(int j=0; j<1000; j++) { for(int k=0; k<1000; k++) { z[i] = a.calc1(x[j], y[k]); } } } cout<<"Not using inline:"<<(clock()-t)/CLK_TCK<<"seconds"<<endl; t = clock(); for(int i=0; i<1000; i++) { for(int j=0; j<1000; j++) { for(int k=0; k<1000; k++) { z[i] = b.calc2(x[j], y[k]); } } } cout<<"Using inline:"<<(clock()-t)/CLK_TCK<<"seconds"<<endl; system("pause"); return 0; } =>Not using inline:99 seconds Using inline:99 seconds (本人用的是Visual Studio 2010,操作系统是Windows 8.1 64位 ,硬盘是希捷 ST500LT012-1DG142)
注:实际测试内联函数并非想象中的高速。
1.5 内联函数的优缺点
- 优点:是提高运行时间效率。
- 缺点:是增加了空间开销。
- 当定义了一个函数后,编译器就会在内存中为其创建一个指令集,当调用这个函数的时候,程序就会跳转到该指令集处,当函数执行完毕后,程序又会回到原来执行调用该函数语句的下一行继续执行。
- 如果对该函数执行上百次调用,那么就要来回跳转上百次,这回严重影响到程序的执行效率。
普通函数:函数调用需要时间和空间开销,调用函数实际上将程序执行流程转移到被调函数中,被调函数的代码执行完后,再返回到调用的地方。
这种调用操作要求调用前保护好现场并记忆执行的地址,返回后恢复现场,并按原来保存的地址继续执行。对于较长的函数这种开销可以忽略不计,但对于一些函数体代码很短,又被频繁调用的函数,就不能忽视这种开销。引入内联函数正是为了解决这个问题,提高程序的运行效率。
内联函数:在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。由于在编译时将内联函数体中的代码替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间开销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。
注:在不知道具体怎么操作时,最好先不要使用内联函数。等完成程序的大部分功能时,再对复合要求的函数进行内联操作。
参考文献:
[1]《C++全方位学习》范磊——第十章
[2]《C++程序设计教程(第二版)》钱能——第五章、第六章、第七章
[3]《C++ Primer(第5版)》王刚 杨巨峰——第一章、第六章
[4] 百度搜索关键字:C++函数、内联函数