#define XXX do{...}while(0)

1、函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。

2、调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。如果是真正的函数,那么它的函数体要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果是函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。

3、定义这种宏要格外小心,要注意括号的使用,和宏展开对运算的优先级的影响。

4、调用函数时先求实参表达式的值再传给形参,如果实参表达式有Side Effect,那么这些Side Effect只发生一次。但如果是宏定义,则可能存在多次Side Effect。

5、即使实参没有Side Effect,使用函数式宏定义也往往会导致较低的代码执行效率。

尽管函数式宏定义和真正的函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。例如C标准库的很多函数都提供两种实现,一种是真正的函数实现,一种是宏定义实现。

例:

#define device_init_wakeup(dev,val) \
        do { \
                device_can_wakeup(dev) = !!(val); \
                device_set_wakeup_enable(dev,val); \
        } while(0)

为什么要用do { ... } while(0)括起来呢?不括起来会有什么问题呢?

#define device_init_wakeup(dev,val) \
                device_can_wakeup(dev) = !!(val); \
                device_set_wakeup_enable(dev,val);

if (n > 0)
 device_init_wakeup(d, v);

这样宏展开之后,函数体的第二条语句不在if条件中。那么简单地用{ ... }括起来组成一个语句块不行吗?

#define device_init_wakeup(dev,val) \
                { device_can_wakeup(dev) = !!(val); \
                device_set_wakeup_enable(dev,val); }

if (n > 0)
 device_init_wakeup(d, v);
else
 continue;

问题出在device_init_wakeup(d, v);末尾的;号,如果不允许写这个;号,看起来不像个函数调用,可如果写了这个;号,宏展开之后就有语法错误,if语句被这个;号结束掉了,没法跟else配对。因此,do { ... } while(0)是一种比较好的解决办法。


中间的device_can_wakeup(dev) = !!(val); 为什么要取反两次呢?

这样做的目的使结果只有两个值“0”和“1”,也就是bool结果,在这里相当于val为0时取0,非0时取1了。

假设一个设备有多个状态,其中val = 0代表没有启用,1,2,3,4分别代表设备启用是处于不同的状态下。那么我就想记录一下设备是否启用了,就可以这样使用:
status = !!(val)
status为0代表未启用,1代表启用了。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值