C++ 函数 内联函数

内联函数的功能和预处理宏的功能相似,在介绍内联函数之前,先介绍一下预处理宏。宏是简单字符替换,最常见的用法:定义了一个代表某个值的全局符号、定义可调用带参数的宏。作为一种约定,习惯上总是用大写字母来定义宏,宏还可以替代字符常量。我们会经常定义一些宏,如:

#define ADD(a,b) a+b

那为什么需要使用宏呢?因为调用函数需要一定的时间和空间开销。

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

而宏仅仅是在预处理的地方把代码展开,不需要额外的时间空间方面的开销。

宏也有很多的不尽人意的地方,所以c++中用内联函数来代替宏。
(1)宏不能访问对象的私有成员。类的私有成员只能通过类的成员函数或友元函数来访问,
(2)宏不进行类型检查。例如上面定义的ADD宏,要注意传入实参的类型,如果你传入的参数不是char, int, float, double,而是其他类型,可能就会出错。
(3)宏的定义很容易产生二义性。

 

#define MULTI(x) (x*x) 

我们用一个数字去调用它,MULTI(10),这样看上去没有什么错误,结果返回100,是正确的;但是如果我们用MULTI(10+10)去调用的话,我们期望的结果是400,而宏的调用结果是(10+10*10+10),结果是120,这显然不是我们要得到的结果。为避免这种错误,可给宏的参数都加上括号。
      

 

 #define MULTI(x) ((x)*(x)) 

这样可以确保MULTI(10+10)不会出错,但是若使用MULTI(a++)调用它,他们本意是希望得到(a+1)*(a+1)的结果,但是宏的展开结果是:(a++)*(a++),如果a的值是2,我们得到的结果是2*3=6。而我们期望的结果是3*3=9。

内联函数的方法很简单,只需在函数首行的左端加一个关键字inline即可 。
在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去,这种嵌入到主调函数中的函数成为内联函数。

 

#include <iostream>
using namespace std;
inline int max(int,int, int);       //声明函数,注意左端有inline
int main( )
{
    int i=10,j=20,k=30,m;
    m=max(i,j,k);
    cout<<″max=″<<m<<endl;
    return 0;
}
inline int max(int a,int b,int c)    //定义max为内置函数
{
    if(b>a) a=b;          //求a,b,c中的最大者
    if(c>a) a=c;
    return a;
}

 

由于在定义函数时指定它为内置函数,因此编译系统在遇到函数调用“max(i,j,k)”时,就用max函数体的代码代替“max(i,j,k)”,同时将实参代替形参。
这样,程序代码“m=max(i,j,k);”就被置换成:
      

 if (j>i) i=j;
 if (k>i) i=k;
        m=i;

 

内联函数必须是和函数体在一起,才有效。如下风格的函数不能成为内联函数:

inline void Fun(int x, int y);  // inline仅与函数声明放在一起
void Fun (int x, int y) {…} 


而如下风格的函数Fun则成为内联函数:

void Fun(int x, int y);
inline void Fun(int x, int y) {…} // inline与函数定义体放在一起 

因此,inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。

内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。内联函数与带参数的宏定义进行下比较,它们的代码效率是一样,但是内联欢函数要优于宏定义,因为内联函数遵循的类型和作用域规则,它与一般函数更相近,在一些编译器中,一旦关联上内联扩展,将与一般函数一样进行调用,比较方便。 

       另外,宏定义在使用时只是简单的文本替换,并没有做严格的参数检查,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。C++的inline的提出就是为了完全取代宏定义,因为inline函数取消了宏定义的缺点,又很好地继承了宏定义的优点

 

内联函数是以代码膨胀(复制)为代价,这省去了函数调用的开销,从而提高函数的执行效率。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)内联函数中不能包括复杂的控制语句,如循环语句和switch语句。如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

同时要注意inline关键字只是表示一个请求,编译器并不会一定将inline修饰的函数作为内联,有的没有被inline修饰的函数在一些编译器中也可能被编译为内联。

 

posted @ 2019-03-19 14:25  王陸  阅读(1648)  评论(1编辑  收藏  举报