do {...} while (0) 的強大

在宏定義中##

如果你是一名C程序員,你肯定很熟悉宏废登,它們非常強大淹魄,如果正確使用可以讓你的工作事半功倍。然而堡距,如果你在定義宏時很隨意沒有認真檢查甲锡,那么它們可能使你發(fā)狂,浪費N多時間羽戒。在很多的C程序中缤沦,你可能會看到許多看起來不是那么直接的較特殊的宏定義。下面就是一個例子:

#define __set_task_state(tsk, state_value)      \
    do { (tsk)->state = (state_value); } while (0)

在Linux內(nèi)核和其它一些著名的C庫中有許多使用do{...}while(0)的宏定義半醉。這種宏的用途是什么疚俱?有什么好處?

Google的Robert Love(先前從事Linux內(nèi)核開發(fā))給我們解答如下:

do{...}while(0)在C中是唯一的構(gòu)造程序缩多,讓你定義的宏總是以相同的方式工作呆奕,這樣不管怎么使用宏(尤其在沒有用大括號包圍調(diào)用宏的語句),宏后面的分號也是相同的效果衬吆。

這句話聽起來可能有些拗口梁钾,其實用一句話概括就是:使用do{...}while(0)構(gòu)造后的宏定義不會受到大括號、分號等的影響逊抡,總是會按你期望的方式調(diào)用運行姆泻。

例如:

#define foo(x) bar(x); baz(x)

然后你可能這樣調(diào)用:

foo(wolf);

這將被宏擴展為:

bar(wolf); baz(wolf);

這的確是我們期望的正確輸出零酪。下面看看如果我們這樣調(diào)用:

if (!feral)
    foo(wolf);

那么擴展后可能就不是你所期望的結(jié)果。上面語句將擴展為:

if (!feral)
    bar(wolf);
baz(wolf);

顯而易見拇勃,這是錯誤的四苇,也是大家經(jīng)常易犯的錯誤之一。

幾乎在所有的情況下方咆,期望寫多語句宏來達到正確的結(jié)果是不可能的月腋。你不能讓宏像函數(shù)一樣行為——在沒有do/while(0)的情況下。

如果我們使用do{...}while(0)來重新定義宏瓣赂,即:

#define foo(x) do { bar(x); baz(x); } while (0)

現(xiàn)在榆骚,該語句功能上等價于前者,do能確保大括號里的邏輯能被執(zhí)行煌集,而while(0)能確保該邏輯只被執(zhí)行一次妓肢,即與沒有循環(huán)時一樣。

對于上面的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語句的確能被正確擴展恭金,但是如果我們有下面的語句調(diào)用呢:

if (!feral)
    foo(wolf);
else
    bin(wolf);

宏擴展后將變成:

if (!feral) {
    bar(wolf);
    baz(wolf);
};
else
    bin(wolf);

大家可以看出,這就有語法錯誤了褂策。

總結(jié):Linux和其它代碼庫里的宏都用do/while(0)來包圍執(zhí)行邏輯横腿,因為它能確保宏的行為總是相同的,而不管在調(diào)用代碼中使用了多少分號和大括號斤寂。

容錯的處理中##

如果系統(tǒng)處理邏輯比較多耿焊,某個過程出現(xiàn)錯誤時,需要退出當前遍搞,但是退出前需要清理一些申請的資源等內(nèi)容罗侯,那么代碼可以這樣寫

void test()
{
    getlock();
    if (!func1()){
        release_lock();
        return;
    }
    if (!func2()){
        release_lock();
        return;
    }
    if (!func3()){
        release_lock();
        return;
    }
    func4();
    release_lock();
}

如果使用do {...} while (0),那么代碼就會很優(yōu)雅,不會出現(xiàn)退出前忘記釋放資源的情況溪猿,如果需要有返回值的情況钩杰,可以在break前為返回值賦值,然后程序最后return即可

void test()
{
    getlock();
    do{
        if (!func1()){
            break;
        }
        if (!func2()){
            break;
        }
        if (!func3()){
            break;
        }
        func4();
    }while(0);
    release_lock();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诊县,一起剝皮案震驚了整個濱河市讲弄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌依痊,老刑警劉巖避除,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓶摆,警方通過查閱死者的電腦和手機凉逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來群井,“玉大人状飞,你說我怎么就攤上這事◎蚪瑁” “怎么了昔瞧?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長菩佑。 經(jīng)常有香客問我自晰,道長,這世上最難降的妖魔是什么稍坯? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任酬荞,我火速辦了婚禮,結(jié)果婚禮上瞧哟,老公的妹妹穿的比我還像新娘混巧。我一直安慰自己,他們只是感情好勤揩,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布咧党。 她就那樣靜靜地躺著,像睡著了一般陨亡。 火紅的嫁衣襯著肌膚如雪傍衡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天负蠕,我揣著相機與錄音蛙埂,去河邊找鬼。 笑死遮糖,一個胖子當著我的面吹牛绣的,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欲账,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屡江,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了敬惦?” 一聲冷哼從身側(cè)響起盼理,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俄删,沒想到半個月后宏怔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奏路,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年臊诊,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸽粉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡抓艳,死狀恐怖触机,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玷或,我是刑警寧澤儡首,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站偏友,受9級特大地震影響蔬胯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜位他,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一氛濒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鹅髓,春花似錦舞竿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至醒串,卻和暖如春重归,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厦凤。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留育苟,地道東北人较鼓。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像违柏,于是被迫代替她去往敵國和親博烂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容