a)⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联函数就不需要建⽴栈帧了,就可以提⾼效率。
b)inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地⽅不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
例如:
下面这个较短小的函数:
#include<iostream>
using namespace std;inline int Add(int a, int b)
{int ret=a + b;return ret;
}int main()
{int ret = Add(1, 2);cout << Add(1, 2) * 5 << endl;return 0;
}
这里通过反汇编的角度,可以看到这里并没有Add函数进行push压栈的操作,没有开辟函数栈帧只是通过call指令,找到这个函数,所以并没有直接调用,只是将其进行替换。
较长的函数:
#include<iostream>
using namespace std;inline int Add(int a, int b)
{int ret=a + b;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;ret += 1;return ret;
}int main()
{int ret = Add(1, 2);cout << Add(1, 2) * 5 << endl;return 0;
}
可以看到这里又进行push操作,说明开辟了函数栈帧,编译器自己处理,判断是直接替换,还是开辟函数栈帧(通常是通过函数的大小来判断)。
c)C语言的宏和inline的比较:
C语⾔实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不⽅便调 试,C++设计了inline⽬的就是替代C的宏函数。
宏具体容易犯的“错”:
示例一:当外面没加括号
#include<iostream>
using namespace std;//正确的#define ADD(X,Y) ((X)+(Y))
#define ADD(X,Y) X+Y
int main()
{cout << ADD(1, 2) * 5 << endl;return 0;
}
这里就会直接替换成1+2*5=11,而不是(1+2)*5=15。
示例二:当里面没加括号
#include<iostream>
using namespace std;//正确的#define ADD(X,Y) ((X)*(Y))
#define ADD(X,Y) (X*Y)
int main()
{cout << ADD(1+2, 2+3) << endl;return 0;
}
这里就会直接替换成1+2*2+3=8,而不是(1+2)*(2+3)=15。
示例三:最后加分号
#include<iostream>
using namespace std;//#define ADD(X,Y) ((X)*(Y))
#define ADD(X,Y) ((X)*(Y));
int main()
{cout << ADD(1+2, 2+3) << endl;return 0;
}
这里也是直接替换(1+2)*(2+3);这里替换将符号也直接替换过去,就会直接报错。
以上都是一些宏容易犯的错误,但用内联函数就可以避免这样的问题。
d)vs编译器debug版本下⾯默认是不展开inline的,这样⽅便调试,debug版本想展开需要设置⼀下 以下两个地⽅。
e)inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址(语法层面),链接时会出现报错。