如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上,这种时间开销就就不容忽视。
为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。
指定内联函数的方法很简单,只需要在函数定义处增加 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;
- }
运行结果: 45 99↙ 45, 99 99, 45 注意,要在函数定义处添加 inline 关键字,在函数声明处添加 inline 关键字虽然没有错,但这种做法是无效的,编译器会忽略函数声明处的 inline 关键字。 当编译器遇到函数调用swap(&m, &n)
时,会用 swap() 函数的代码替换swap(&m, &n)
,同时用实参代替形参。这样,程序第 16 行就被置换成:
- int temp;
- temp = *(&m);
- *(&m) = *(&n);
- *(&n) = temp;
编译器可能会将 *(&m)、*(&n) 分别优化为 m、n。 当函数比较复杂时,函数调用的时空开销可以忽略,大部分的 CPU 时间都会花费在执行函数体代码上,所以我们一般是将非常短小的函数声明为内联函数。 由于内联函数比较短小,我们通常的做法是省略函数原型,将整个函数定义(包括函数头和函数体)放在本应该提供函数原型的地方。下面的例子是一个反面教材,这样的写法是不被推荐的:
- #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;
- }
使用内联函数的缺点也是非常明显的,编译后的程序会存在多份相同的函数拷贝,如果被声明为内联函数的函数体非常大,那么编译后的程序体积也将会变得很大,所以再次强调,一般只将那些短小的、频繁调用的函数声明为内联函数。