2016-01-15 50 views
1

我最近看到一段C代碼,包括下面的樣式宏:爲什麼「do ... while(0)」不能被簡單的花括號替換?

#define TOTO()    \ 
do {      \ 
    do_something();   \ 
    do_another_something(); \ 
} while (0) 

我起初不知道這裏的do while (0)的目的,但this answer向我解釋說:這是在情況下,宏是一種ifelse沒有大括號後剛剛使用,就像這樣:所以在這裏

if (something) 
    TOTO(); 
else 
    do_something_else(); 

,沒有do while (0)聲明,代碼將擴大到:

if (something) 
    do_something(); 
    do_another_something(); 
else 
    do_something_else(); 

這在語法上是錯誤的,因爲else不再直接跟在if作用域之後。

但我認爲它可以通過在自己的範圍內聲明宏來工作,而不需要圍繞它的do while,所以我只用大括號測試了相同的代碼。我的整個代碼如下所示:

#include <stdio.h> 

#define HELLO_WORLD()  \ 
{       \ 
    printf("hello ");  \ 
    printf("world!\n");  \ 
} 

int  main(int argc, char** argv) 
{ 
    if (argc == 1) 
     HELLO_WORLD(); 
    else 
     fprintf(stderr, "nope\n"); 
    return 0; 
} 

但是GCC給我下面的錯誤:

error: ‘else’ without a previous ‘if’

然而,main函數的代碼應擴大到:

if (argc == 1) 
    { 
     printf("hello "); 
     printf("world!\n"); 
    } 
else 
    fprintf(stderr, "nope\n"); 
return 0; 

哪已驗證。

那麼我在這裏錯過了什麼?

+3

您在'HELLO_WORLD()'之後放入的分號 –

+1

一如以往面對與宏相關的問題:編譯器可能會有一個開關來輸出預處理文件,因此您可以看到代碼編譯器的實際輸入是什麼樣子。 – usr2564301

+0

@Downvoters這是一個糟糕的問題?這是重複的,是的,但是至少將其標記爲一個,而不是downvoting,並告訴每個人這是一個糟糕的問題。或者這是什麼原因? – Downvoter

回答

9

它是宏後面的分號。

宏擴展到這個代替:

if (argc == 1) 
    { 
     printf("hello ");  \ 
     printf("world!\n");  \ 
    }; 
else  // HERE, SYNTAX ERROR 
    fprintf(stderr, "nope\n"); 
return 0; 

既然應該有一個if語句來的身體和else -clause之間沒有分號,這是一個語法錯誤。
OTOH,一個do - while循環允許(和需要)分號。


只需打印真正的預處理器輸出,就可以輕鬆避免關於編譯器輸出的誤解。這可以通過使用

  • -E開關的gcc可執行文件。從man 1 gcc

-E Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.

  • 預處理器直接在cpp可執行的形狀。

由於
- @dhke用於校正在發生錯誤的行。
- @kakeh提供預先查看預處理器輸出的建議。

2

仔細看你如何調用宏。

你不得不寫

if (argc == 1) 
    HELLO_WORLD() // NO SEMICOLON!!!!!!! 
else 
    fprintf(stderr, "nope\n"); 

這將是godawful,因爲你永遠無法與真正的功能替換程序hello_world宏。