2010-12-15 151 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"

如果考虑使用表达式而非单个标记调用您的宏,请将括号中出现的每个参数括在括号中,原因与上述相同。

要避免的另一件事是传递具有副作用的表达式作为宏参数。如果相应的宏参数在其定义中被多次引用,那么评估将被执行多次,而这通常不是我们所期望的。