C++ 内联函数详解

内联函数
在函数运行的时候都有一些额外的开销,比如a函数调用b函数,在调用b函数的时候先要把a函数暂停,给b函数分配一块内存空间,再进行参数的传递,把实际参数的值拷贝给形式参数,接下去再执行b函数,函数执行结束以后,将b函数的空间收回,最后把b函数中的返回值返回到a函数,然后a函数再继续执行,所以函数调用过程中有这些额外的代价。如果一个函数很复杂,函数本身就要运行很长时间,这些额外的代价可以忽略,分配空间和参数传递是可以忽略的时间;但是如果这个函数本身就很简单,执行的时间挺短,那函数调用产生额外的代价就非常的可观,所以函数调用也有不好的地方,浪费时间,执行效率低。但是如果不写成函数的形式,对程序的可读性有一定影响,所以C++提出了内联函数,可以有函数的形式,让函数保持模块化可读性良好的特性,但是又没有函数调用的代价。

特点:

  • 有函数的形式,但无函数调用的代价
  • 编译时用函数体代码替代函数调用

定义

inline 返回类型 函数名(形式参数列表)

指定内联函数,只需要在函数定义处增加 inline 关键字
函数定义必须出现在函数调用之前

实例

#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 << "\n";
  cout<< "c =" << c << ", c squared = " << square(c++) << "\n";
  cout<< "Now c = " << c << "\n";

  return 0;
}

运行结果:
a = 25, b = 144
c = 13, c squared = 169
Now c = 14

内联函数与宏定义

  • inline是函数,宏不是函数。
  • 内联函数可以调试,进行诸如类型安全检查、语句是否正确等编译功能;宏不具有这样的调试功能;
  • 宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。
  • 内联函数是在编译时展开,而宏在预编译时展开;在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。

使用宏代码最大的缺点是容易出错,预处理在拷贝宏代码时常常产生意向不到的边际效应。
例如:

#define MAX(a,b) (a)>(b)?(a):(b)

语句:

result = MAX(i,j)+2;
//被预处理器扩展为 
result = (i)>(j)?(i):(j)+2;

由于运算符"+“比运算符”?:"的优先级高,所以上述语句并不等价于

result = ((i)>(j)?(i):(j))+2;

如果把宏代码改写为:

#define MAX(a,b) ((a)>(b)?(a):(b))

则能解决优先级的问题。但是会引发另一个问题

result = MAX(i++,j);

//被预处理器扩展为

result = (i++)>(j)?(i++):(j) //在同一个表达式中i被两次求值。

内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员,所以应该尽量使用内联函数来取代宏代码。

何时使用内联函数
内联能提高函数的执行效率,那么为什么不把所有的函数都定义成内联函数呢?
内联不是万灵丹,它以代码膨胀(拷贝)为代价,仅仅省去了函数调用的开销,从而提高程序的执行效率。(开销指的是参数的压栈、跳转、退栈和返回操作)。

一方面,如果执行函数体内代码的时间比函数调用的开销大得多,那么inline效率收益会很小。
另一方面,每一处内联函数的调用都要拷贝代码,使程序的总代码量增大,消耗更多的内存空间。

以下情况不宜使用内联:

如果函数体内代码比较长,使用内联函数将导致可执行代码膨胀过大。
如果函数体内出现循环或者其他复杂的控制结构,那么执行函数体内代码的时间将比函数调用的开销大得多。

总结:当函数比较复杂时,函数调用的时空开销可以忽略,大部分的 CPU 时间都会花费在执行函数体代码上,这时使用内联效率很低,而且会导致代码膨胀过大。所以我们一般是将非常短小的、频繁调用的函数声明为内联函数,以提高执行效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值