C/C++中do...while(0)的妙用
2014-03-09 15:34
176 查看
【本文转载了2篇blog关于do...while(0)的巧妙用法,这两篇文章内容水平很高,在此谢谢原文作者,如需转载请保留原文作者的连接(而不是我的连接)。原文如下:
http://www.devbean.net/2014/01/do-while-in-macro/ http://www.cppblog.com/SmartPtr/archive/2007/07/03/27443.html
】
参考链接:http://www.pixelstech.net/article/1390482950-do-%7B-%7D-while-%280%29-in-macros
虽然我们不建议使用宏,但是,作为一个语言特性,有时宏是不可避免的。对于这种情况,正确使用宏尤其重要。它可以帮助你减少很多重复性工作。但是,如果你没有仔细地定义,宏绝对能把你逼疯。在很多 C/C++ 程序中,你会看到类似如下定义的宏:
宏的语句被
C 库,包括 Linux 内核中,这种情形都不少见。这种红如何使用?来自 Google 的 Robert Love(他曾经是 Linux 内核开发人员)给了我们答案。
之后,我们这样调用:
foo(wolf);
宏将被展开为
bar(wolf); baz(wolf);
这正是正确的结果。下面,我们来看另外一种情况:
此时,宏展开结果为:
这很可能不是你所期望的。
也就是说,我们所定义的这个宏并不适用于所有使用它的情形。没有
如果我们将这个宏使用
现在,这个语句与之前的那个在功能上是等价的。通过将语句嵌于花括号之内,我们保证了整个逻辑不会被宏外面的分号打断;
语义上说,它等价于:
或许你会问,为什么不仅仅使用一对花括号就好了?为什么必须要有
如此定义,上面的展开语句仍然正确。但是对于C++程序员来讲,在么个语句后面加分号是一个约定成俗的习惯,这样的话,我们考虑另外一种情况:
这种写法将被展开为:
现在我们有了一个语法错误,所以采用do...while(0)是最好的选择了。
也许你会说,我们代码的习惯是在每个判断后面加上{}, 就不会有这种问题了,也就不需要do...while了,如:
诚然,这是一个好的,应该提倡的编程习惯,但一般这样的宏都是作为library的一部分出现的,而对于一个library的作者,他所要做的就是让其库具有通用性,强壮性,因此他不能有任何对库的使用者的假设,如其编码规范,技术水平等。
总结一下,在 Linux 或其它代码库中的宏使用
####################################################################################################################################
【以下内容来自:http://www.cppblog.com/SmartPtr/archive/2007/07/03/27443.html】
在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;
}
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
// 执行成功,释放资源并返回
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;
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
// 执行成功,释放资源并返回
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;
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
}while(0);
// 释放资源
delete p;
p = NULL;
return bOk;
}
“漂亮!”, 看代码就行了,啥都不用说了...
http://www.devbean.net/2014/01/do-while-in-macro/ http://www.cppblog.com/SmartPtr/archive/2007/07/03/27443.html
】
参考链接:http://www.pixelstech.net/article/1390482950-do-%7B-%7D-while-%280%29-in-macros
虽然我们不建议使用宏,但是,作为一个语言特性,有时宏是不可避免的。对于这种情况,正确使用宏尤其重要。它可以帮助你减少很多重复性工作。但是,如果你没有仔细地定义,宏绝对能把你逼疯。在很多 C/C++ 程序中,你会看到类似如下定义的宏:
#define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0)
宏的语句被
do{...}while(0)包围起来。在很多
C 库,包括 Linux 内核中,这种情形都不少见。这种红如何使用?来自 Google 的 Robert Love(他曾经是 Linux 内核开发人员)给了我们答案。
do{...}while(0)是 C 语言中唯一能让宏后面加上分号还能够正确工作的语法结构。使用
do{...}while(0)包围起来,我们就不需要担心宏被如何使用。例如:
#define foo(x) bar(x); baz(x)
之后,我们这样调用:
foo(wolf);
宏将被展开为
bar(wolf); baz(wolf);
这正是正确的结果。下面,我们来看另外一种情况:
if (!feral) foo(wolf);
此时,宏展开结果为:
if(!feral) bar(wolf); baz(wolf);
这很可能不是你所期望的。
也就是说,我们所定义的这个宏并不适用于所有使用它的情形。没有
do{...}while(0)语句,我们不可能写出类似函数的宏。
如果我们将这个宏使用
do{...}while(0)语句重新定义,那么就会是这样的:
#define foo(x) do { bar(x); baz(x); } while (0)
现在,这个语句与之前的那个在功能上是等价的。通过将语句嵌于花括号之内,我们保证了整个逻辑不会被宏外面的分号打断;
while(0)则保证这个逻辑片段只执行一次,这和没有循环是一致的。使用改进过的宏,上述语句会被展开为:
if(!feral) do{bar(wolf);baz(wolf);}while(0);
语义上说,它等价于:
if (!feral) { bar(wolf); baz(wolf); }
或许你会问,为什么不仅仅使用一对花括号就好了?为什么必须要有
do{...}while(0)?例如,我们这样定义宏:
#define foo(x) { bar(x); baz(x); }
如此定义,上面的展开语句仍然正确。但是对于C++程序员来讲,在么个语句后面加分号是一个约定成俗的习惯,这样的话,我们考虑另外一种情况:
if (!feral) foo(wolf);
else
bin(wolf);
这种写法将被展开为:
if(!feral){ bar(wolf); baz(wolf); }; else bin(wolf);
现在我们有了一个语法错误,所以采用do...while(0)是最好的选择了。
也许你会说,我们代码的习惯是在每个判断后面加上{}, 就不会有这种问题了,也就不需要do...while了,如:
if( ... ) { ... // do sth. foo(x); } else { ...//do sth. }
诚然,这是一个好的,应该提倡的编程习惯,但一般这样的宏都是作为library的一部分出现的,而对于一个library的作者,他所要做的就是让其库具有通用性,强壮性,因此他不能有任何对库的使用者的假设,如其编码规范,技术水平等。
总结一下,在 Linux 或其它代码库中的宏使用
do{...}while(0)包围其逻辑,这保证了宏在使用时,不管宏所在的位置花括号、分号如何写,宏的表现总是一致的。
####################################################################################################################################
【以下内容来自:http://www.cppblog.com/SmartPtr/archive/2007/07/03/27443.html】
在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;
}
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
// 执行成功,释放资源并返回
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;
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
// 执行成功,释放资源并返回
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;
//
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
![](http://www.cppblog.com/Images/dot.gif)
.
}while(0);
// 释放资源
delete p;
p = NULL;
return bOk;
}
“漂亮!”, 看代码就行了,啥都不用说了...
相关文章推荐
- C++ do...while(0) do...while(false)的妙用
- 【C++基础 03】do...while(0)妙用
- 【C++基础 03】do...while(0)妙用
- C/C++中的do-while循环的妙用
- C/C++中do...while(0)的妙用
- 【C++基础 03】do...while(0)妙用
- c++ do while(0) 原理
- do { }while(0)的妙用
- do...while(0)的妙用
- C++巧用do...while(0)
- do...while(false)的妙用
- C++常考笔试题:不用if,while,do-while,for,打印出所有大于0小于k的整数.函数原型void printLess(int k);
- do...while(0)的妙用
- do...while(0)的妙用
- do...while(0) do...while(false)的妙用
- do…while(0)的妙用
- do...while(0)的妙用
- do...while(0)的妙用
- do...while(0)的妙用
- C++上机报告 分别用3种循环(while~、for(;;)~、do~while)计算下式