在 Linux 內核、嵌入式 SDK 等工業級 C 代碼中,`do { ... } while(0)` 是多語句宏的標準包裝模式。它解決了普通宏在控制流語句中引發的**語法錯誤**與**邏輯錯誤**。
#define FOO(x) foo(x); bar(x)
if (cond) FOO(x); else ...;
// 展開後
if (cond) foo(x); bar(x); else ...; // 語法錯誤:else 無匹配 if
if (cond) FOO(x);
// 展開後
if (cond) foo(x); bar(x); // bar(x) 無條件執行!
#define FOO(x) do { foo(x); bar(x); } while(0)
現在宏展開為**單一語句**,可安全用於任何控制流上下文:
if (cond) FOO(x); else ...; // 正確
while (cond) FOO(x); // 正確
for (...) FOO(x); // 正確
將多語句合併為單一復合語句,配合尾隨分號,完美適配 `if/else/while/for/switch` 等所有需要單語句的場景。
#define FOO(x) do { OTHER_FOO(x); } while(0)
無論 `OTHER_FOO` 是單語句、復合語句、甚至另一個 `do-while(0)` 宏,外層宏展開後語法均合法。無需關心內層宏結構。
#define FOO(x) do { \
foo(x); \
if (error(x)) break; /* 跳出包含該宏的最近循環 */ \
bar(x); \
} while(0)
在循環中調用 `FOO(x)` 時,`break` 可跳出**外層循環**,而非僅跳出宏內部(宏內部無循環)。這為錯誤處理提供了類函數的控制流能力。
#define FOO(x) { foo(x); bar(x); }
if (cond) FOO(x); else ...;
// 展開: if (cond) { foo(x); bar(x); } ; else ...; // 語法錯誤:多餘分號導致 else 懸空
復合語句 `{}` 後不能跟分號,而 `do-while(0)` **必須**跟分號,完美匹配 C 語句語法。
`do {} while(0)` 是 C 宏編程的**設計模式**:零運行開銷(編譯器優化掉空循環),換取極致的語法安全性與組合靈活性。請在所有多語句宏中強制使用。