奇怪的宏定义问题

时间:2010-12-15 21:51:16

标签: c macros c-preprocessor

我想在编译时根据另一个宏的值定义一个宏。但是,此代码未按预期执行:

#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++) {
...

有谁能解释这里发生了什么?

3 个答案:

答案 0 :(得分: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))
            ^                                                       ^

使用宏时,最好在任何地方使用括号,以确保结果符合您的预期。

答案 1 :(得分:2)

始终将宏括在括号中,因为您并不总是知道将使用它的上下文 - 可能会发生相邻运算符具有更高优先级并且宏将无法正确计算。

如果#define'd符号是单个标记,例如5"hello world",则不使用括号是合理的。

如果考虑使用表达式而不仅仅是单个标记调用宏,请将该参数的每个匹配项括在括号中,原因与上述相同。

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

答案 2 :(得分:1)

展开宏,并在宏扩展后查看for循环:

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

请参阅? i < (16 % 8 == 0)?:运算符的条件。您需要在TWO的定义周围添加一对括号。