inline内联函数
c程序执行过程就是不同函数互相调用的过程,但是函数调用是有时间和空间开销的,函数调用需要执行入栈出栈操作。如果函数很复杂,执行时间长,那么入栈出栈的操作相比之下可以忽略,但如果函数较简单,那么相比之下入栈出栈的开销就不能忽略了。因此c++提供了一种代码替换的方法,就是内联函数inline。在编译时用函数体替换调用语句,类似于宏定义。又称为内置函数。
#include <iostream> using namespace std; //内联函数,交换两个数的值 inline void swap(int *a, int *b){ int temp; temp = *a; *a = *b; *b = temp; } int main(){ int m, n; cin>>m>>n; cout<<m<<", "<<n<<endl; swap(&m, &n); cout<<m<<", "<<n<<endl; return 0; }
内联函数的定义和声明要写在一起,不推荐下面分开的写法
#include <iostream> using namespace std; //声明内联函数 void swap1(int *a, int *b); //也可以添加inline,但编译器会忽略 int main(){ int m, n; cin>>m>>n; cout<<m<<", "<<n<<endl; swap1(&m, &n); cout<<m<<", "<<n<<endl; return 0; } //定义内联函数 inline void swap1(int *a, int *b){ int temp; temp = *a; *a = *b; *b = temp; }
内联函数的缺点很明显,编译后程序中会存在多分相同函数的拷贝,如果内联函数比较大,那么编译后的程序体积也会很大,所以内联函数一般都是那些短小且调用频繁的函数。
内联函数不是强制性的,对函数做inline声明只是程序员对编译器提出的一个建议,编译过程中并不一定会百分百进行函数体替换。
相比与宏定义,内联函数更安全,宏定义只是字符替换,并没有参数检查,而函数是有参数检查的,而且宏定义很容易因为优先级的问题踩坑,写的时候需要很小心,但是内联函数相比之下就不用那么费心。
#include <iostream> using namespace std; #define SQ(y) y*y int main(){ int n, sq; cin>>n; sq = SQ(n+1); cout<<sq<<endl; return 0; }
宏被替换成了n+1*n+1,优先级错误,所以应该改为#define SQ(y) (y)*(y)
#include <iostream> using namespace std; #define SQ(y) (y)*(y) int main(){ int n, sq; cin>>n; sq = 200 / SQ(n+1); cout<<sq<<endl; return 0; }
这次宏被替换成了200/(n+1)*(n+1),同样出现了优先级错误,所以要改成#define SQ(y) ((y)*(y))
就很心累,但如果用内联函数来写的话就轻松很多了
#include <iostream> using namespace std; inline int SQ(int y){ return y*y; } int main(){ int n, sq; cin>>n; //SQ(n) sq = SQ(n); cout<<sq<<endl; //SQ(n+1) sq = SQ(n+1); cout<<sq<<endl; //200 / SQ(n+1) sq = 200 / SQ(n+1); cout<<sq<<endl; return 0; }
宏定义是在预处理阶段展开,内联函数是在编译时展开,这也是两者的一个区别
内联函数的编写规范
内联函数不应该有函数声明,要把内联函数定义在它应该声明的地方。
再多文件编程中,经常把函数的定义放在源文件中,把函数的声明放在头文件中,这样调用函数时只要引入头文件即可,这种将函数定义和生命分开的做法是正确的,但是并不适用于内联函数,内联函数的定义和生命分散到不同文件中会出现错误。
main.cc
#include <iostream> using namespace std; //内联函数声明 void func(); int main(){ func(); return 0; }
module.cc
#include <iostream> using namespace std; //内联函数定义 inline void func(){ cout<<"inline function"<<endl; }
代码可以通过编译,但是连接时会出错,因为内联函数在编译时会展开,替换,编译完成后内联函数就不存在了,所以链接的时候就会找不到函数的定义。
函数的本质是一段复用的代码,存在于虚拟内存的代码区中,也占有可执行文件的一部分体积。内联函数虽然语法和函数一样,但他再编译后从虚拟内存的代码区中消除了。
因此从代码复用的角度来讲,内联函数已经不算是函数了,内联函数更像是宏定义的一个替换方案,而不是当作一个正常函数来使用。
多文件编程时直接在头文件中定义内联函数,不要把定义和声明分开。