c++: 内联函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_19923217/article/details/84871747

我们知道,函数封装调用有利于代码的重复利用,因为我们可以函数起一个通俗易懂的名字,因此阅读和理解函数通常比读懂等价的条件表达式容易的多。

然而函数相较于等价表达式运行速度要慢一些,因为在大多数机器上,一次函数调用意味着其实包含一系列的工作:调用前先保存寄存器,并在返回时恢复;可能需要拷贝实参;程序转向一个新的位置继续执行;

内联函数的出现就是为了避免不必要的函数调用的开销,将函数定义为内联函数,通常将它在每个调用点上“内联”展开。

首先我们先熟悉下函数调用的原理

1. 函数调用的原理

编译过程的最终产品是可执行程序(由一组机器语言指令组成)。运行程序时,操作系统将这些指令载入计算机内存中,因此每条指令都有特定的内存地址。计算机随后将逐步执行这些指令。有时(如有循环和分支语句时),将跳过一些指令,向前或向后跳到特定地址。

常规函数调用也使程序跳到另一个地址(函数的地址),并在函数结束时返回。执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还需将返回值放入寄存器中),然后跳回到地址被保存的指令处(这与阅读文章时停下来看脚注,并在阅读完脚注后返回到以前阅读的地方类似)。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。

2. 内联函数

内联函数提供了另一种选择。编译器将使用相应的函数代码替换函数调用。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。

函数使用直接在函数声明或定义前加 inline 即可

inline const string& shortString(...)
{
    ...
}

示例如下:

#include<iostream>

inline double square(double x){return x*x;}

int main()
{
    using namespace std;
    double a,b;
    double c = 13.0;
    
    a = square(5.0);
    b = square(4.5 + 7.5);
    cout << "a=" << a << ",b=" << b << endl;
    cout << "c=" << c << endl;
    cout << "c squared=" << square(c++) << endl;
    cout << "now c=" << c << endl;
    
    return 0;
}

程序输出结果如下:

a=25,b=144
c=13
c square=169
now c=14

3. 内联函数与宏定义的区别

C 语言使用预处理器语句 #define 来提供宏,与内联函数的使用比较像,下面具体说明下两者的区别。

如下例所示:

#define SQUARE(X) X*X

宏定义时通过文本替换开实现的–X 是参数的符号标记。

a = square(5.0);  // -> a=5.0*5.0;
b = square(4.5+7.5); // -> b=4.5+7.5*4.5+7.5
d = square(c++); // -> d=c++*c++

可以看出,对于 b,需要使用括号才能正常运算。

#define SQUARE(X) ((X)*(X))

对于 c,却仍递增了两次。

因此,宏定义和内联函数存在本质的区别,转换的时候应考虑是否转换后功能是否正常。

4. 什么时候使用内联函数

  1. 如果函数执行代码的时间很短,优于处理函数调用的时间,则内联函数就能体现作用。因此,一个较为合理的经验准则是, 不要内联超过 10 行的函数。
  2. 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行)。
  3. 内联函数定义在头文件中,不要放在 cpp 文件中

猜你喜欢

转载自blog.csdn.net/qq_19923217/article/details/84871747