2010-12-15 50 views
0

我想在編譯時根據另一個宏的值定義一個宏。但是這個代碼不執行如預期:奇怪的宏定義問題

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define SIXTEEN 16 
#define TWO (SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1) 

int main(); 

int main() { 
    printf("max = %d\n", TWO); 
    int i; 
    for (i = 0; i < TWO; i++) { 
     printf("%d\n", i); 
    } 
    return 0; 
} 

此打印:

max = 2 
0 
1 
2 
... 

,並一直持續到終止,當它應該是簡單的打印:

max = 2 
0 
1 

和退出。

如果我這樣做,相反,它的工作原理:

#define TWO 2 

我認爲這是與宏的定義問題......但是,如果我這樣做與原來的#define以下,這似乎工作:

... 
int count = TWO; 
for (i = 0; i < count; i++) { 
... 

任何人都可以解釋這裏發生了什麼?

回答

11

的問題是,所述令牌TWO由與所定義的宏令牌更換,所以這一點:

i < TWO 

變成這樣:

i < (SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1) 

由於操作者優先的,這是閱讀爲:

(i < (SIXTEEN % 8 == 0)) 
    ? (SIXTEEN/8) 
    : ((SIXTEEN/8) + 1) 

您需要額外的括號,以便當TWO被其替換列表所取代,你得到你想要的結果:

#define TWO ((SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1)) 
      ^             ^

使用宏時,這是最好的地方,你可以確保結果是你所期望的使用括號。

+0

+1打我37秒。 =( – 2010-12-15 21:55:33

+2

+1)一般的經驗法則是:如果你的宏應該擴展成一個表達式,那麼確保它被包含在一對(匹配的)parens中。一個例外是如果它保證擴展成一個單一的記號(像OP的SIXTEEN宏)。 – 2010-12-15 21:59:17

1

展開宏,看看你for循環宏展開後:

for (i = 0; i < (16 % 8 == 0)? (16/8) : ((16/8) + 1); i++) 

看到了嗎? i < (16 % 8 == 0)是運營商?:的條件。您需要圍繞TWO的定義放置一對括號。

2

總是將宏放在括號中,因爲您並不總是知道它將被使用的上下文 - 可能發生的情況是相鄰的運算符具有更高的優先級,並且宏將無法正確評估。

不使用括號只有在#define'd符號是單個令牌時纔有效,例如5"hello world"

如果考慮使用表達式而非單個標記調用您的宏,請將括號中出現的每個參數括在括號中,原因與上述相同。

要避免的另一件事是傳遞具有副作用的表達式作爲宏參數。如果相應的宏參數在其定義中被多次引用,那麼評估將被執行多次,而這通常不是我們所期望的。