zoukankan      html  css  js  c++  java
  • 第9章 内联函数

      C中,保持效率的一个方法是使用宏。宏可以不要普通的函数调用代价就可使之看起来像函数调用。宏的实现是用预处理器而不是编译器。预处理器直接用宏代码代替宏调用,所以就没有了参数压栈、生成汇编语言的CALL、返回参数、执行汇编语言的RETURN等的开销。所有的工作由预处理器来完成,因此不用花费什么就具有了程序调用的便利和可读性。

      在C++中,使用预处理器宏存在两个问题。第一个问题在C中也存在:宏看起来像一个函数调用,但并不总是这样。这样就隐藏了难以发现的错误。第二个问题是C++特有的:预处理器不允许访问类的成员数据。这意味着与处理器宏不能用作类的成员函数。

      为了既保持预处理器宏的效率又增加安全性,而且还能像一般成员函数一样可以在类里访问自如,C++引入了内联函数。

     

      预处理器的缺陷

       这里存在两个问题。

       第一个问题是表达式在宏内展开,所以它们的优先级不同于所期望的优先级,例如:

        #define FLOOR(x,b) x >= b ? 0:1

      现在假如用表达式作参数:

        if(FLOOR(a&0x0f,0x07)) // ...

      宏将展开成:

        if(a&0x0f >= 0x07 ? 0:1)

      因为&的优先级比>=的低,所以宏的展开结果将会使我们惊讶。一旦发现这个问题,可以通过在宏定义内的各个地方使用括弧来解决。上面的定义可改写成如下:

        #define FLOOR(x,b) ((x) >= (b) ? 0:1)

      前面的问题可以通过谨慎地编程来解决:在宏中将所有的内容都用括号括起来。第二个问题则复杂一些。不像普通函数,每次在宏中使用一个参数,都对这个参数求值。

      例如,下面这个宏决定它的参数是否在一定范围:

        #define BAND(x) (((x) > 5 && (x) < 10) ? (x) : 0)

      只要使用一个“普通”参数,宏和真的函数的工作方式非常相似。但下面的问题出现了:

        for(int i = 4;i < 11;i++) {
          int a = i;
          out << “a = “ << a << endl << ‘	’;
          out << “BAND(++a) = “ << BAND(++a) << endl;
          out << “	 a = “ << a << endl;
        }                

      运行结果并不是预期想要得到的。所以像这样的问题可能隐藏了一些难以发现的错误。

     

      内联函数

      内联函数能够像普通函数一样具有我们所有期望的任何行为。惟一不同之处是内联函数在适当的地方像宏一样展开,所以不需要函数调用的开销。

      任何在类中定义的函数自动地成为内联函数,但也可以在非类的函数前面加上inline关键字使之成为内联函数。但为了使之有效,必须使函数体和声明结合在一起,否则,编译器将它作为普通函数对待。因此

        inline int plusOne(int x);

      没有任何效果,仅仅只是声明函数,成功的方法如下:

        inline int plusOne(int x) { return ++x; }

      一般应该把内联定义放在头文件里。

     

      为了定义内联函数,通常必须在函数定义前面放一个inline关键字。但这在类内部定义内联函数时并不是必须的。任何在类内部定义的函数自动地成为内联函数。

      但应注意,使用内联函数的目的是减少函数调用的开销。但是,假如函数较大,由于需要在调用函数的每一处重复复制代码,这样将使代码膨胀,在速度方面获得的好处就会减少。

     

      限制

      有两种编译器不能执行内联的情况。在这些情况下,它就像对非内联函数一样。

      假如函数太复杂,编译器将不能执行内联。

      假如要显式地或隐式地取函数地址,编译器也不能执行内联,因为这时编译器必须为函数代码分配内存从而产生一个函数的地址。

  • 相关阅读:
    java 正则 二次转义
    HDU1789 Doing Homework again 【贪心】
    扣丁学堂笔记第22天多媒体播放
    [Python]BeautifulSoup—HTML解析包
    Android高级控件(三)——&#160;使用Google ZXing实现二维码的扫描和生成相关功能体系
    Business Process and SAP ERP
    HTML基础知识总结一
    控制器View是怎样创建的?
    cocos2d-x 3.0 场景切换特效汇总
    LeetCode 3Sum
  • 原文地址:https://www.cnblogs.com/sheshiji/p/3428531.html
Copyright © 2011-2022 走看看