• 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修饰的函数在一些编译器中也可能被编译为内联。

  • 相关阅读:
    验证整数 Double 转 int 两种写法
    0 can't find referenced pointcut declarePointExpress
    nested exception is java.lang.IllegalArgumentException: Pointcut is not well-formed
    org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML doc
    嵌入式系统(胡威)2019年春第一次作业 参考答案
    PAT(B) 1021 个位数统计(Java)
    PAT(B) 1020 月饼(Java)
    PAT(B) 1019 数字黑洞(Java)
    PAT(B) 1018 锤子剪刀布(C:20分,Java:18分)
    PAT(B) 1017 A除以B(Java)
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/10558446.html
Copyright © 2020-2023  润新知