define do{} while(0) 用法妙用

define do{} while(0) 

用法妙用

 

2010-12-10 11:44 

#define 

 

 

do{} while(0) 

什么意思

 

#define 

 

 

do{} while(0) 

为什么这么用

 

什么情况下用宏定义

do{}while(0); 

 

 

简单地说,就是能够实现复杂的定义,通用性强,任

何情况下都适用。

 

 

 

#define MACRO_NAME(para) do{macro content}while(0) 

的格式,总结了以下几个原因:

 

1

,空的宏定义避免

warning: 

 

 

 

 

 

 

#define foo() do{}while(0) 

 

 

2

,存在一个独立的

block

,可以用来进行变量定义,进行比较复杂的实现。

 

3

,如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现:

 

 

 

 

 

 

#define foo(x) \ 

 

 

 

 

 

 

action1(); \ 

 

 

 

 

 

 

action2(); 

 

 

 

 

 

在以下情况下:

 

 

 

 

 

if(NULL == pPointer) 

 

 

 

 

 

 

 

 

 

foo(); 

 

 

 

 

 

 

就会出现

action1

action2

不会同时被执行的情况,而这显然不是程序设计的目的。

 

 

 

 

 

 

 

4

,以上的第

3

种情况用单独的

{}

也可以实现,但是为什么一定要一个

do{}while(0)

呢,

看以下代码:

 

 

 

 

 

 

 

#define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;} 

 

 

 

 

 

 

 

 

 

 

if(x>y) 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

switch(x,y); 

 

 

 

 

 

 

 

 

else 

 

 

 

 

 

 

//error, parse error before else 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

otheraction(); 

 

 

 

 

 

 

在把宏引入代码中,会多出一个分号,从而会报错。

 

 

 

 

 

 

 

 

 

//------------------------------------------------ 

 

 

 

 

 

 

 

使用

do{….}while(0)

 

把它包裹起来,成为一个独立的语法单元,从而不会与上下文

发生混淆。同时因为绝大多数的编译器都能够识别

do{…}while(0)

这种无用的循环并进行优

化,所以使用这种方法也不会导致程序的性能降低。

 

详解如下:

MFC, 

MFC

afx.h

文件里面,

 

你会发现很多宏定义都是用了

do...while(0)

do...while(false)

 

比如说:

 

#define 

AFXASSUME(cond) 

 

 

 

 

 

 

do 

bool 

__afx_condVal=!!(cond); 

ASSERT(__afx_condVal); __analysis_assume(__afx_condVal); } while(0) 

 

粗看我们就会觉得很奇怪,既然循环里面只执行了一次,我要这个看似多余的

do...while(0)

有什么意义呢?

 

 

当然有!

 

为了看起来更清晰,这里用一个简单点的宏来演示:

 

#define SAFE_DELETE(p) do{ delete p; p = NULL} while(0) 

假设这里去掉

do...while(0), 

#define SAFE_DELETE(p) delete p; p = NULL; 

那么以下代码:

 

if(NULL != p) SAFE_DELETE(p) 

else 

 

 

...do sth... 

就有两个问题,

 

1) 

因为

if

分支后有两个语句,

else

分支没有对应的

if

,编译失败

 

2) 

假设没有

else, SAFE_DELETE

中的第二个语句无论

if

测试是否通过,会永远执行。

 

你可能发现,为了避免这两个问题,我不一定要用这个令人费解的

do...while, 

 

我直接用

{}

括起来就可以了

 

#define SAFE_DELETE(p) { delete p; p = NULL;} 

的确,这样的话上面的问题是不存在了,但是我想对于

C++

程序员来讲,在每个语句后面加

分号是一种约定俗成的习惯,这样的话,以下代码

if(NULL != p) SAFE_DELETE(p); 

else 

 

 

...do sth... 

else

分支就无法通过编译了(原因同上)

,所以采用

do...while(0)

是做好的选择了。

 

 

也许你会说,我们代码的习惯是在每个判断后面加上

{}, 

就不会有这种问题了,也就不需要

do...while

了,如:

 

if(...) 

 

else 

诚然,这是一个好的,应该提倡的编程习惯,但一般这样的宏都是作为

library

的一部分出现

的,而对于一个

library

的作者,他所要做的就是让其库具有通用性,强壮性,因此他不能有

任何对库的使用者的假设,如其编码规范,技术水平等

 

 

 

 

do...while(0)-

妙用

 

 

(

...)sswanglei 

发表于

 

2007-7-1 

22:33:00 

C++

中,有三种类型的循环

语句:

for, while, 

do...while

 

但是在一般应用中作循环时,

 

我们可能用

for

while

要多

一些,

do...while

相对不受重视。

 

 

 

 

 

但是,最近在读我们项目的代码时,却发现了

do...while

的一些十分聪明的用法,不是用

来做循环,而是用作其他来提高代码的健壮性。

 

1. do...while(0)

消除

goto

语句。

 

通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出

函数,当然,退出前先释放资源,我们的代码可能是这样:

 

version 1 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

bool

 bOk(

true

); 

 

 

 

 

// 

执行并进行错误处理

 

 

 

 

bOk = func1(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

bOk = func2(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

bOk = func3(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

// ..........

 

 

 

 

 

// 

执行成功,释放资源并返回

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

true

 

 

 

 

 

 

 

这里一个最大的问题就是代码的冗余,而且我每增加一个操作,就需要做相应的错误处理,

非常不灵活。于是我们想到了

goto: 

version 2

 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

bool

 bOk(

true

); 

 

 

 

 

// 

执行并进行错误处理

 

 

 

 

bOk = func1(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

bOk = func2(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

bOk = func3(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

// ..........

 

 

 

 

 

// 

执行成功,释放资源并返回

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

true

 

errorhandle: 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

代码冗余是消除了,但是我们引入了

C++

中身份比较微妙的

goto

语句,虽然正确的使用

goto

可以大大提高程序的灵活性与简洁性,

但太灵

 

活的东西往往是很危险的,

它会让我们的程序

捉摸不定,那么怎么才能避免使用

goto

语句,又能消除代码冗余呢,请看

do...while(0)

循环:

 

version3 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

 

bool

 bOk(

true

); 

 

 

 

do

 

 

 

 

 

 

 

 

 

 

// 

执行并进行错误处理

 


 

 

 

 

 

 

bOk = func1(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

bOk = func2(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

bOk = func3(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

// ..........

 

 

 

 

 

}

while

(0); 

 

 

 

 

 

// 

释放资源

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 bOk;


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值