奇怪的宏定义问题

Jas*_*ank 0 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;
}
Run Code Online (Sandbox Code Playgroud)

这打印:

max = 2
0
1
2
...
Run Code Online (Sandbox Code Playgroud)

并继续直到终止,当它应该打印简单:

max = 2
0
1
Run Code Online (Sandbox Code Playgroud)

并退出.

如果我这样做,它的工作原理:

#define TWO 2
Run Code Online (Sandbox Code Playgroud)

我认为这是宏的定义的一个问题...但是,如果我使用原始的#define执行以下操作,它似乎工作:

...
int count = TWO;
for (i = 0; i < count; i++) {
...
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*lis 11

问题是令牌TWO被您定义宏的令牌所取代,因此:

i < TWO
Run Code Online (Sandbox Code Playgroud)

成为这个:

i < (SIXTEEN % 8 == 0)? (SIXTEEN / 8) : ((SIXTEEN / 8) + 1) 
Run Code Online (Sandbox Code Playgroud)

由于运算符优先级,因此读为:

(i < (SIXTEEN % 8 == 0))
    ? (SIXTEEN / 8) 
    : ((SIXTEEN / 8) + 1) 
Run Code Online (Sandbox Code Playgroud)

您需要额外的括号,以便当TWO替换为替换列表时,您将获得所需的结果:

#define TWO ((SIXTEEN % 8 == 0)? (SIXTEEN / 8) : ((SIXTEEN / 8) + 1))
            ^                                                       ^
Run Code Online (Sandbox Code Playgroud)

使用宏时,最好尽可能使用括号来确保结果符合您的预期.

  • +1一般的经验法则是:如果你的宏应该扩展成一个表达式,那么确保它被包含在一对(匹配)的parens中.唯一的例外是它是否可以保证扩展为单个令牌(如OP的SIXTEEN宏). (2认同)