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;
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;