在嵌入式开发中,宏定义非常强大和方便。如果使用得当,它可以让你的工作更有效率。但是,在很多C程序中,你可能会看到不太直接和特殊的宏定义,例如do{}while(0)。do{条件代码}while(条件)结构的流程图如下:总体结构如下!!while()do的意思是看你先行不行!当你第一次在Linux内核和其他开源代码中看到do{...}while(0)时,经常会遇到这样的代码:do{...}while(0)这种代码一开始并不是循环一眼。从表面上看,do..while在这里根本没有任何意义,只执行一次,为什么要这么用呢?总结了7种美其实do{...}while(0)的作用不止一点点,下面我会列举一些。有时它比仅将{}用于代码分块更直观。例如,在cocos2d-x代码中做{CCImage*pImage=newCCImage();CC_BREAK_IF(NULL==pImage);bRet=pImage->initWithString(text,(int)dimensions.width,(int)dimensions.height,eAlign,fontName,(int)fontSize);CC_BREAK_IF(!bRet);bRet=initWithImage(pImage);CC_SAFE_RELEASE(pImage);}while(0);2.宏展开,不会报错。比如直接放在花括号里,就会报错。例如,假设您需要定义这样一个宏:#defineDOSOMETHING()action1();action2();这个宏的初衷是在执行DOSOMETHING()时,会调用action1(),action2()。如果有判断,则执行这个宏,如下:if(NULL==pPointer)DOSOMETHING();else...这样在预处理的时候会直接展开这个宏放在花括号里,然后实际写代码如下:if(NULL==pPointer)action1();action2();else...这个展开有两个问题:因为if分支后面有两条语句,else分支没有a对应if,编译失败。假设没有else分支,无论if测试通过与否,都会执行DOSOMETHING中的第二条语句。那么就用{}包裹action1()和action2()?例如:#defineDOSOMETHING(){action1();action2();}我们在写代码的时候习惯在语句的右边加一个分号。如果在宏中使用了{},宏就相当于代码编译展开后这样写。After:{...};,展开后如下:if(NULL==pPointer){action1();action2();};else...这段代码中大括号后面有一个分号,如果有else,则没有相应的ifforelse,出现编译错误。那么如果我们使用do{...}while(0)来定义宏,解决方案就来了,即:#defineDOSOMETHING()\do{\action1();\action2();\}while(0)\macro是展开最后,上面的调用语句会保留原来的语义,同时,大部分编译器都可以识别出do{...}while(0)这个无用循环,并在不降低性能优化的情况下对其进行优化。小结在Linux内核和驱动代码以及cocos2d-x中,很多宏的实现都是使用do{...}while(0)来包装它们的逻辑。Google的RobertLove(之前从事Linux内核开发)给了我们如下的回答:“让你定义的宏总是以同样的方式工作,不管调用代码中如何使用分号和花括号,宏总是可以确保它的行为是一致的。3.当你执行一段代码到一半时,当你想跳过剩下的一半时,如果你在一个do{...}while(0)循环中,你可以使用break来实现这个目标。做{执行。再次执行...if(如果满足任何条件){我想跳转到另一段代码,剩下的不执行,但是不建议使用goto语句,怎么办?break;/*getit*/}我可能会被执行。}while(false)例如,do{if(!a)break;//dosomethinghereif(!b)break;//doanotherthinghere}while(0);4.变形的goto,有些公司不允许使用goto。在某些函数中,需要实现条件传递,或者形成一个循环,跳出循环体。使用goto总是一个简单的方法,例如:#include
