宏的注意事项

1.防止错误展开

 

 

请注意宏定义中出现的所有这些括号,它们的作用是预防引起与优先级有关的问题。

 

例如,假设宏abs被定义成了这个样子:

让我们来看abs(a-b)求值后会得到怎样的结果。表达式

abs(a-b)

会被展开为

a-b>0?a-b:-a-b

这里的子表达式-a-b不是我们期望的-(a-b),因此上式无疑会得到一个错误的结果。因此,我们最好在宏一定中把每个参数都用括号括起来。同样,整个结果表达式也应该用括号括起来,以防止当宏用于一个更大一些的表达式中可能出现的问题。如果不这样,

 

abs(a)+1

展开后的结果为:

a>0?a:-a+1

这个表达式很显然是错误的。


2.防止二次重算

 

 

一个操作数如果在两处被用到,就会被求值两次。例如,在表达式max(,ab)中,如果a大于b,那么a将被求值两次:第一次是在a与b比较期间,第二次是在计算max应该得到的结果值时。

这种做法不但效率低下,而且可能是错误的:

如果max是一个真正的函数,上面的代码可以正常工作;而如果max是一个宏,那么就不能正常工作。要看清楚这一点,我们首先初始化数组x中的一些元素:

x[0] = 2;

x[1] = 3;

x[2] = 1;

然后考擦在循环的第一次迭代时会发生上面。上面代码中的赋值语句将被扩展为:

首先,变量biggest将与x[i++]比较。因为i此时的值是1,x[1]的值是3,而变量biggest此时的值是x[0]即2,所以关系运算的结果为false。这里,因为i++的副作用,在比较后i递增为2。

因为关系运算的结果为false,所以x[i++]的值将被赋给变量biggest。然而,经过i++的递增运算后,i此时的值是2。所以,实际上赋给变量biggest的值是x[2],即1。这时,又因为i++的副作用,i的值成为3。

解决这类问题的一个办法是,确保宏max中的参数没有副作用。

另一个办法是让max作为函数而不是宏,或者直接编写比较两数取较大者的运算的代码。


3.宏的效益

 

 

使用宏的另一个危险是,宏展开可能产生非常庞大的表达式,占用的空间远远超过了编程者所期望的空间。例如,让我们再看宏max的定义:

假定我们需要使用上面定义的宏max,来找到a、b、c、d四个数的最大者,最显而易见的写法是:

上面的式子展开后就是:

确实,这个式子太长了!

其实,写成以下代码似乎更容易一些:

 


4.宏不是类型定义

 

考虑下面的代码:

从上面两个定义来看,T1和T2从概念上完全符同,都是指向结构foo的指针。但是,当我们试图用它们来声明多个变量时,问题就来了:

第一个声明被扩展为:

这个语句中a被定义为一个指向结构的指针,而b却被定义为一个结构(而不是指针。第二个声明则不同,它定义了a和b都是指向结构的指针,因为这里T2的行为完全与一个真实的类型相同。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值