巨集定義為什麼要使用do while 0 形式

2021-08-06 00:07:43 字數 2724 閱讀 7827

如果你是一名c程式設計師,你肯定很熟悉巨集,它們非常強大,如果正確使用可以讓你的工作事半功倍。然而,如果你在定義巨集時很隨意沒有認真檢查,那麼它們可能使你發狂,浪費n多時間。在很多的c程式中,你可能會看到許多看起來不是那麼直接的較特殊的巨集定義。下面就是乙個例子: 1

2

#define __set_task_state(tsk, state_value)      \

dowhile(0)

在linux核心和其它一些著名的c庫中有許多使用dowhile(0)的巨集定義。

這種巨集的用途是什麼?有什麼好處?

google的robert love(先前從事linux核心開發)給我們解答如下:

dowhile(0)在c中是唯一的構造程式,讓你定義的巨集總是以相同的方式工作,這樣不管怎麼使用巨集(尤其在沒有用大括號包圍呼叫巨集的語句),巨集後面的分號也是相同的效果。

這句話聽起來可能有些拗口,其實用一句話概括就是:使用dowhile(0)

構造後的巨集定義不會受到大括號、分號等的影響,總是會按你期望的方式呼叫執行。

例如: 1

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

然後你可能這樣呼叫:

1

foo(wolf);

這將被巨集擴充套件為:

1

bar(wolf); baz(wolf);

這的確是我們期望的正確輸出。下面看看如果我們這樣呼叫:

1

2

if(!feral)

foo(wolf);

那麼擴充套件後可能就不是你所期望的結果。上面語句將擴充套件為:

1

2

3

if(!feral)

bar(wolf);

baz(wolf);

顯而易見,這是錯誤的,也是大家經常易犯的錯誤之一。

幾乎在所有的情況下,期望寫多語句巨集來達到正確的結果是不可能的。你不能讓巨集像函式一樣行為——在沒有do/while(0)的情況下。

如果我們使用dowhile(0)來重新定義巨集,即:

1

#define foo(x) do while (0)

現在,該語句功能上等價於前者,do能確保大括號裡的邏輯能被執行,而while(0)能確保該邏輯只被執行一次,即與沒有迴圈時一樣。

對於上面的if語句,將會被擴充套件為:

1

2

if(!feral)

dowhile(0);

從語義上講,它與下面的語句是等價的:

1

2

3

4

if(!feral)

這裡你可能感到迷惑不解了,為什麼不用大括號直接

把巨集包圍起來呢?

為什麼非得使用do/while(0)邏輯呢?

例如,我們用大括號來定義巨集如下:

1

#define foo(x)

這對於上面舉的if語句的確能被正確擴充套件,但是如果我們有下面的語句呼叫呢:

1

2

3

4

if(!feral)

foo(wolf);

else

bin(wolf);

巨集擴充套件後將變成:

1

2

3

4

5

6

if(!feral) ;

else

bin(wolf);

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

**:

為什麼巨集定義要使用16進製制呢

如 define sdl init timer 0x00000001 define sdl init audio 0x00000010 define sdl init video 0x00000020 define sdl init cdrom 0x00000100 define sdl init ...

為什麼要使用blog

有哥們問我,你為什麼使用blog?我總結了一下,覺得有如下幾個原因。1對自己的督促 有了blog,就會經常記得寫點東西 就會經常翻翻網上的新文章,了解一下新技術,不至於迷失在忙碌的生活中 如果把自己的所感所想所學寫出了,自己對自己也會有個概念,不至於迷迷糊糊 還有,畢竟是掛在網上的文字,心中難免擔心...

為什麼要使用XML

xml 代表擴充套件標記語言 extensible markup language 是由 world wide web consortium w 3c 的 xml工作組定義的。這個工作組是這樣描述該語言的 擴充套件標記語言 xml 是 sgml 的子集,其目標是允許普通的 sgml 在web 上以目...