《Thinking in C++, 2nd Edition》笔记-第九章(Inline Functions)

在C中,宏可以用来提高效率,宏的实现是用预处理器而不是编译器。预处理器直接用宏代码代替调用,所以就没有了参数压栈、生成汇编语言的CALL、返回参数、执行汇编语言的RETURN的时间花费。所有的工作由预处理器完成,因此,不用花费什么就具有了程序调用的便利和可读性。C++中,使用预处理器宏存在两个问题。第一个问题在C中也存在:宏看起来像一个函数用,但并不总是这样。这就隐藏了难以发现的错误。第二个问题是C++特有的:预处理器不许存取私有( private )数据。这意味着预处理器宏在用作成员函数时变得非常无用。因此,C++用了内联函数。

预处理器的缺陷

示例1:

#define f (x) (x+1);

这里f和(x)之间不小心加了一个空格,因此,使用时f(1)的结果是(x) (x+1)(1),显然不是我们希望看到的。

示例2:

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

if(floor(a&0x0f,0x07))  // ...
宏将展开成:
if(a&0x0f>=0x07?0:1) 

因为&的优先级比>=低,因此也出现了错误的结果。

示例3:

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

band(x)很像一个函数了,但是如果这样使用:

int i = 5;

band(++i);

显然也会出现问题。

class X {
int i;
public :
#define val (X::i)  //Error
所以如果想效率的存取i,只能把它当作public变量,但这显然又破坏了封装性。

内联函数

在C++中,宏的概念是用内联函数来实现的,而内联函数是真正的函数。唯一不同的是内联函数在适当时像宏一样展开,所以函数调用的开销被消除。因此,最好不使用宏,只使用内联函数。

一般应该把内联定义放在头文件里。当编译器看到这个定义时,它把函数类型(函数名和返回值)和函数体放到符号表里。当使用函数时,编译器确保正确的调用,然后将函数调用替换为函数体,因而消除了开销。内联代码的确占用空间,但假如函数较小,这实际上比为了一个普通函数调用而产生的代码(参数压栈和执行CALL)占用的空间还少。因此,假如函数较大,那么花费在函数体内的时间相对于进出函数的时间的比例就会较大,所以好处会较少,而且函数调用的地方进行了代码复制,造成代码膨胀。所以在函数太复杂时,编译器多数情况下会放弃内联。假如要显式或隐含地取一个函数的地址,编译器也不能对这个函数执行内联,因为这时编译器必须为函数代码分配内存,从而为我们产生一个函数的地址。

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

对一个成员变量的存取,就可以用内联函数,一方面节省了函数调用的开销,另一方面代码短小。同时,避免了成员变量的直接访问。


class Forward { 
  int i; 
public: 
  Forward() : i(0) {} 
  // Call to undeclared function: 
  int f() const { return g() + 1; } 
  int g() const { return i; } 
}; 
以上代码并不会有问题,f中使用了内联函数g,但g在h之后声明,这并没有关系,因为C++规定,非内联函数直到类声明结束才赋值。

预编译宏的优势

预编译宏有3个特别的特征无法被内联替代:字符串定义,字符串串联和标志粘贴。#可以将一个标志符转换成一个字符串。

#define DEBUG(X)  cout<<#X " = " << X << endl          可以打印任何变量的值

#define TRACE(S) cout << #S << endl; S           打印它们执行的语句,比如TRACE(f(i)) ;第二句的S是执行这个语句,前面的分号用逗号可以避免一些前面所说的宏定义的问题。

#define FIELD(a) char* a##_string; int a##_size 
class Record { 
  FIELD(one); 
  FIELD(two); 
  FIELD(three); 
  // ... 
};  
每次调用这个宏,都会产生两个变量:一个字符指针,一个字符串长度。##可以把两个标志符粘贴在一起,生成一个新的标志符。

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值