do{conditional code}while(condition)
結構流程圖如下:一般結構如以下代碼
do
{
//循環體
}
while (條件表達式);
意思是先幹了再說!!
意思是先看看能不能幹!
linux內核和其他一些開源的代碼中,經常會遇到這樣的代碼:
do{
...
}while(0)
這樣的代碼一看就不是一個循環,do..while表面上在這裡一點意義都沒有,只執行一次而已,那麼為什麼要這麼用呢?
實際上,do{...}while(0)的作用可不止一點點,下面我列舉了一些。
cocos2d-x
代碼中 do
{
CCImage* pImage = new CCImage();
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);
舉例來說,假設你需要定義這樣一個宏:
#define DOSOMETHING() action1(); action2();
這個宏的本意是,當執行DOSOMETHING()時,action1(),action2()都會被調用。如果有判斷,再執行這個宏的話,如下:
if(NULL == pPointer)
DOSOMETHING();
else
...
這樣宏在預處理的時候會直接被展開,放在花括號裡,那麼實際上寫的代碼如下:
if(NULL == pPointer)
action1();
action2();
else
...
這展開存在兩個問題:
那麼僅僅使用{}把action1()、action2()包起來行麼?比如:
#define DOSOMETHING() { action1(); action2(); }
我們在寫代碼的時候都習慣在語句右面加上分號,如果在宏中使用{},代碼編譯展開後宏就相當於這樣寫了:{...};
,展開後如下:
if(NULL == pPointer)
{
action1();
action2();
};
else
...
這段代碼中大括號後多了一個分號,如果有else,那麼else又沒有對應的if了,編譯出錯。
如果我們使用do{...}while(0)
來定義宏,即:
#define DOSOMETHING() \
do{ \
action1();\
action2();\
}while(0)\
宏被展開後,上面的調用語句會保留初始的語義,同時絕大部分編譯器都能夠識別do{...}while(0)
這種無用的循環並進行優化,不會導致性能優化的降低。
在Linux內核和驅動代碼還有cocos2d-x
中,很多宏實現都使用do{...}while(0)
來包裹他們的邏輯,Google的Robert Love
(先前從事Linux內核開發)給我們解答如下:
「讓你定義的宏總是以相同的方式工作,不管在調用代碼中怎麼使用分號和大括號,而該宏總能確保其行為是一致的。
do{...}while(0)
循環中,則能用break達到這個目的。 do
{
執行.
再執行…
if (如果有什麼條件滿足)
{
我想跳到另外一段代碼了,剩下的不執行了,可是不建議用goto語句,怎麼辦呢?
break;/*搞定*/
}
我有可能被執行.
}while(false)
舉個例子如下
do
{
if(!a) break;
//do something here
if(!b) break;
//do another thing here
}while(0);
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str;
/* 最初的內存分配 */
str = (char *) malloc(15);
if(str != NULL)
goto loop;
printf("hello world\n");
loop:
printf("malloc success\n");
return(0);
}
但由於goto不符合軟體工程的結構化,而且有可能使得代碼難懂,所以很多人都不倡導使用,這個時候我們可以使用do{...}while(0)
來做同樣的事情:
#include <stdio.h>
#include <stdlib.h>
int main()
{
do{
char *str;
/* 最初的內存分配 */
str = (char *) malloc(15);
if(str != NULL)
break;
printf("hello world\n");
}while(0);
printf("malloc success\n");
return(0);
}
這裡將函數主體部分使用do{...}while(0)
包含起來,使用break來代替goto,後續的清理工作在while之後,現在既能達到同樣的效果,而且代碼的可讀性、可維護性都要比上面的goto代碼好的多了。
int a;
a = 10;
int b;
b = 20;
這種代碼在只支持c89的編譯器上是編譯不過去的,比如ADS 2.0。
int a;
a = 10;
do
{
int b;
b = 20;
}while(0);
do{...}while(0)
來定義空宏: #define DOSOMETHING() do{}while(0)
如果你有一個複雜的函數,變量很多,而且你不想要增加新的函數,可以使用do{...}while(0)
,將你的代碼寫在裡面,裡面可以定義變量而不用考慮變量名會同函數之前或者之後的重複,例如
int key;
string value;
int func()
{
int key = GetKey();
string value = GetValue();
dosomething for key,value;
do{
int key;string value;
dosomething for this key,value;
}while(0);
}
但是為了代碼的可讀性,儘量聲明不同的變量名,以便於後續開發人員欣賞