宏语句 do{/*...*/}while(0)

【转载请注明出处: http://blog.csdn.net/lzl124631x/article/details/14222113

有时程序中重复出现某几条语句, 为了保证程序DRY(Don't Repeat Yourself), 需要将这几条语句合并为一条语句.

在C++中可以选择用 inline, C语言没有这个特性, 但是可以用宏实现.

正确答案是用 do{ /* Your Code Here. */ }while(0) 实现, 下面推理下为什么这种方法最好吧.


思路一: 直接写在一起

比如要将 i++; j++; 这两条语句封装在一起.

#define INC(i, j) i++; j++

这样不满足原子性, 在某些情况下两条语句可能被拆开, 如:

if(1)
	INC(i, j);

实际上被拆成了:
if(1)
	i++;
j++;

思路二: 花括号

#define INC(i, j) { i++; j++; }
原子性满足了, 但是仍然会在某些情况下出错, 如:

if(bool)
	INC(i, j);
else
	/* Code For Else */;

此时相当于:

if(bool){
	i++; j++;
};
else
	/* Code For Else */;
此时是会报错的, else 被一个空语句 ; 断开了.


思路三: 逗号表达式

#define INC(i, j) i++, j++ // or: ( i++, j++ )
看上去还不错, 程序会按照逗号表达式从左至右执行.

但是...如果想在宏语句里面定义局部变量怎么办?

比方我想写一个 SWAP 函数交换两个变量, 需要用一个临时变量.

#define SWAP(i, j) (int tmp, tmp = i, i = j, j = tmp)

这样是无法编译通过的...

而且, 逗号表达式中无法加入 if , break 等语句.

#define INC(i) if(1) i++ // OK
#define INC(i) (if(1) i++) // ERROR
#define INC(i) (i++, if(1) i++) // ERROR
#define INC(i) (i++, break, i++) // ERROR


思路四: do{/*...*/}while(0)

#define SWAP(i, j) do{int tmp = i; i = j; j = tmp; }while(0)

这技巧其实很普遍, 人们说是Linux内核中常用的技巧.

这么写至少有三条好处:

  1. 具有原子性, 语句不会被拆开;
  2. 可以定义临时变量;
  3. 可以通过插入 break; 语句在该宏语句的中间退出执行. 此技巧可用于异常控制, 类似 try...catch.


我第一次是在我编译的 WebKit 内核中见到的.

WebKit 的词法分析利用自动机的原理在状态之间进行跳转, 跳转的过程中可能要频繁进行一些操作, 如:

// HTMLTokenizer.cpp
#define HTML_RECONSUME_IN(stateName) RECONSUME_IN(HTMLTokenizerState, stateName)

// MarkupTokenizerInlineMethods.h
#define RECONSUME_IN(prefix, stateName)                                    \
    do {                                                                   \
        m_state = prefix::stateName;                                       \
        goto stateName;                                                    \
    } while (false)
这个代码用来在状态之间进行直接跳转, 跳转的过程中需要将当前状态 m_state 设置为目标状态 prefix::stateName, 然后 goto 跳转到该状态.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值