当前位置:编程学习 > C/C++ >>

内联函数之一

在C中,保护效率的一个方法是使用宏( m a c r o )。宏可以不用普通函数调用就使之看起来像
函数调用。宏的实现是用预处理器而不是编译器。预处理器直接用宏代码代替宏调用,所以就没有了参数压栈、生成汇编语言的CALL、返回参数、执行汇编语言的RETURN的时间花费。
所有的工作由预处理器完成,因此,不用花费什么就具有了程序调用的便利和可读性。
C++中,使用预处理器宏存在两个问题。第一个问题在C中也存在:宏看起来像一个函数调用,但并不总是这样。这就隐藏了难以发现的错误。第二个问题是C++特有的:预处理器不容许存取私有(private)数据。这意味着预处理器宏在用作成员函数时变得非常无用。
为了既保持预处理器宏的效率又增加安全性,而且还能像一般成员函数一样可以在类里访问自如,C + +用了内联函数

1.预处理器存在的缺陷
预处理器宏存在的关键问题是我们可能认为预处理器的行为和编译器的行为一样。当然,
有意使宏在外观上和行为上与函数调用一样,因此容易被混淆
在宏调用中使用表达式作为参数时,当表达式在宏内展开,它们的优先级可能不同于我们所期望的优先级。这会产生些意想不到的问题。但是我们可以在编程的时候通过人为的方式来避免,给每一个表达式都加上一个括号。
利用宏对参数求值也会产生某些出乎意料的错误,因为它并不能完全模仿函数的行为
例如:
#define band(x) ((x)>5 && (x)<10? (x):0)
功能是判断x是否位于5和10之间,是则返回x的值,否则返回0
int a=8;//显然满足条件
cout<<band(++a);
输出的结果是0
因为宏展开时执行了两次++a,第一次判断(x)>5,此时a=9,第二次判断(x)<10,此时a=10。所以最后返回的结果并没用达到我们的预期。
对于C++,由于预处理器仅仅的简单的执行原文替代,所以想在类中通过定义一个public的宏作为一个成员函数来对私有成员进行处理是不行的。

2.内联函数
在解决C++中宏存取私有的类成员的问题过程中,所有和预处理器宏有关的问题也随着消失了。这是通过使宏被编译器控制来实现的。在C++中,宏的概念是作为内联函数来实现的,而内联函数无论在任何意义上都是真正的函数。唯一不同之处是内联函数在适当时像宏一样展开,所以函数调用的开销被取消。因此,应该永远不使用宏,只使用内联函数。
任何在类中定义的函数自动地成为内联函数,但也可以使用inline关键字放在类外定义的函数前面使之成为内联函数。但为了使之有效,必须使函数体和声明结合在一起,否则,编译器将它作为普通函数对待。因此
inline int PlusOne(int x);
没有任何效果,仅仅只是声明函数(这不一定能够在稍后某个时候得到一个内联定义)。成功的方法如下:
inline int PlusOne(int x) { return ++x ;}
注意,编译器将检查函数参数列表使用是否正确,并返回值(进行必要的转换)。这些事情是预处理器无法完成的。假如对于上面的内联函数,我们写成一个预处理器宏的话,将有不想要的副作用。
一般应该把内联定义放在头文件里。当编译器看到这个定义时,它把函数类型(函数名+返回值)和函数体放到符号表里。当使用函数时,编译器检查以确保调用是正确的且返回值被
正确使用,然后将函数调用替换为函数体,因而消除了开销。内联代码的确占用空间,但假如函数较小,这实际上比为了一个普通函数调用而产生的代码(参数压栈和执行C A L L)占用的空间还少。

在头文件里,内联函数默认为内部连接——即它是static,并且只能在它被包含的编译单元看到。因而,只要它们不在相同的编译单元中声明,在内联函数和全局函数之间用同样的名字也不会在连接时产生冲突。

 


3.类内部的内联函数
在类内部定义内联函数,inline关键字并不是必须的。任何在类内部定义的函数自动地为内联函数。
当然,因为类内部的内联函数节省了在外部定义成员函数的额外步骤,所以我们一定想在类声明内每一处都使用内联函数。但应记住,内联的目的是减少函数调用的开销。假如函数较大,那么花费在函数体内的时间相对于进出函数的时间的比例就会较大,所以收获会较小。而且内联一个大函数将会使该函数所有被调用的地方都做代码复制,结果代码膨胀而在速度方面获得的好处却很少或者没有。

 


 

补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,