为什么我需要在此定义中括起x和y?

时间:2014-08-26 16:46:48

标签: c macros c-preprocessor modulo

我使用这个#define宏来计算数组的索引

#define index(x, y) (((x) % 5) + ((y) % 5) * 5)

如果我删除(x)和(y)的大括号

#define index(x, y) ((x % 5) + (y % 5) * 5)

结果不同。

有人可以解释一下这种行为吗?我这样用:

uint64_t a[25];
...
unsigned int x,y;
uint64_t C[5];
for (y = 0; y < 5; y++) {
  for (x = 0; x < 5; x++) {
    C[x] = a[index(x, y)] ^ ((~a[index(x + 1, y)]) & a[index(x + 2, y)]);
  }
  for (x = 0; x < 5; x++ ) {
    a[index(x, y)] = C[x];
  }
} 

5 个答案:

答案 0 :(得分:3)

根据第一个定义,这个:

index(x + 1, y)

扩展为:

(((x + 1) % 5) + ((y) % 5) * 5)

第二个,它扩展为:

((x + 1 % 5) + (y % 5) * 5)

问题是x + 1 % 5。由于%的优先级高于+,因此它等同于x + (1 % 5),这不是您想要的。

扩展宏时,预处理器会扩展令牌序列。它没有注意运算符优先级。

类似的例子:https://github.com/Keith-S-Thompson/42

#include <stdio.h>

#define SIX 1+5
#define NINE 8+1

int main(void)
{
    printf("%d * %d = %d\n", SIX, NINE, SIX * NINE);
    return 0;
}

答案 1 :(得分:1)

因为宏参数是有效的复制粘贴代码:

鉴于此:

#define index(x, y) ((x % 5) + (y % 5) * 5)

然后这就是转型

a[index(x + 1, y)]
a[((x + 1 % 5) + (y % 5) * 5)]

请注意第一部分:

   (x + 1 % 5)

这正是为什么每本教学书都应该提到你应该在括号中包装宏参数。

答案 2 :(得分:0)

因为当你使用:

#define index(x, y) ((x % 5) + (y % 5) * 5)

index(x + 1, y)被视为index((x + 1 % 5) + (y % 5) *5)

由于modulo(%)的优先级高于+,因此结果错误。

查看优先级表here

答案 3 :(得分:0)

始终在宏参数周​​围添加括号。

宏扩展在编译之前发生,它只是替换参数的文本,因为它们在代码中。在预编译时,没有要解释的值,因此必须使用括号来保持操作的顺序。

在您的示例中,宏index(x + 1, y)已扩展为:

((x + 1 % 5) + (y % 5) * 5)

由于模运算符优先于加法,1 % 5在加到x之前计算结果为1。

答案 4 :(得分:0)

嗯,你不必,但它可能会导致奇怪的情况。 #defines会直接进行文本替换,所以想象一下这种情况:

#define foo(x) (x << 1)
...
int r = 1;
int y = foo( r + 1 );

y的价值是多少? 您最想要的是y = 4。这是R加1,然后向左移1 但实际上你得到y = 3。为什么?直接替换和操作顺序优先。

预处理器替换如下:

y = r + 1 << 1;

由于班次具有更高的预测性,因此它会在添加之前发生。

现在,将此应用于您的示例,在此行中:

C[x] = a[index(x, y)] ^ ((~a[index(x + 1, y)]) & a[index(x + 2, y)]);
                                   ^^^^^^                ^^^^^

这些部分引起了你的不同,当替换发生时没有括号你得到第一部分:

index(x + 1, y)] .....  (x + 1 % 5) + (y % 5) * 5)
                          ^^^^^^^^^

看到问题? 1%5 = 1因此x总是加1 而括号:

index(x + 1, y)] .....  ((x + 1) % 5) + ((y) % 5) * 5)
                          ^^^^^^^^^

你会得到你期望的行为x + 1,然后是mod 5.