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;
}

代码可以通过编译,但是连接时会出错,因为内联函数在编译时会展开,替换,编译完成后内联函数就不存在了,所以链接的时候就会找不到函数的定义。

函数的本质是一段复用的代码,存在于虚拟内存的代码区中,也占有可执行文件的一部分体积。内联函数虽然语法和函数一样,但他再编译后从虚拟内存的代码区中消除了。

因此从代码复用的角度来讲,内联函数已经不算是函数了,内联函数更像是宏定义的一个替换方案,而不是当作一个正常函数来使用。

多文件编程时直接在头文件中定义内联函数,不要把定义和声明分开。

上一篇:Linux异步IO引擎:io-uring


下一篇:sq表