do...while(0)的用法
来源:互联网 发布:高维稀疏数据 编辑:程序博客网 时间:2024/05/29 08:40
1.在宏定义中的用法
使用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)
现在,该语句功能上等价于前者,do能确保大括号里的逻辑能被执行,而while(0)能确保该逻辑只被执行一次,即与没有循环时一样。
对于上面的if语句,将会被扩展为:
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); }
这对于上面举的if语句的确能被正确扩展,但是如果我们有下面的语句调用呢:
if (!feral) foo(wolf);else bin(wolf);
宏扩展后将变成:
if (!feral) { bar(wolf); baz(wolf);};else bin(wolf);
大家可以看出,这就有语法错误了。
总结:Linux和其它代码库里的宏都用do/while(0)来包围执行逻辑,因为它能确保宏的行为总是相同的,而不管在调用代码中使用了多少分号和大括号。
2.消除goto语句
通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样:
Version1:
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: Version2:
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; }
使用break语句,十分漂亮。
3.参考
1.http://www.cnblogs.com/flying_bat/archive/2008/01/18/1044693.html
2.http://www.cnblogs.com/lanxuezaipiao/p/3535626.html
- do...while(0)的用法
- do{} while(0)的用法
- do{...}while(0)的用法
- do while(0)的用法
- do...while(0)的用法
- do {} while (0) 用法
- do while(0) 用法
- do...while(0)用法
- do{}while(0)用法
- do{}while(0)用法
- do{...}while(0)的用法小结
- do{}while(0)控制结构的用法
- do while(0)宏的用法
- MACRO do-while(0) 的几个用法
- MACRO do-while(0) 的几个用法
- do{...}while(0)的意义和用法
- do{...}while(0)的意义和用法
- do{...}while(0)的意义和用法
- android所读的书籍
- Java设计模式之代理模式
- 复制之clipboardData剪贴板
- Ubuntu 安装 VMware注册码
- 51NOD 1191 消灭兔子
- do...while(0)的用法
- 电商总结-日志监控系统的解决方案
- 整数中1出现的次数(从1到n整数中1出现的次数)--数学规律法
- 启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- js的outerHTML 与jquery的prop()的用法
- JAVA----文本框、label、jcombobox初始化设置
- Qt之高级网络操作(HTTP/FTP快速上手)
- 公司有固定加班时间
- leetCode_Palindrome Partitioning II