无法获得宏和运算符优先级背后的逻辑

时间:2012-12-31 12:09:23

标签: c c-preprocessor

以下代码的输出是8 24 32.我理解8和24背后的逻辑,但32对我来说似乎很奇怪。有人可以解释为什么打印32?

#define cube(x) x*x*x
void main()
{
    printf("%d ",cube(2));
    printf("%d ",16+cube(2));
    printf("%d ",16/cube(2));
}

5 个答案:

答案 0 :(得分:4)

最后printf被翻译为:

printf("%d ",16/2 * 2 * 2);

这就是为什么所有的宏都应该有周围的括号:

#define cube(x) ((x)*(x)*(x))

或者只是使用函数并信任编译器内联它们。功能几乎总是更好。

答案 1 :(得分:3)

宏只是文本 1 的编译时替换。所以C预处理器将改变这一行:

 printf("%d ",16/cube(2));

到这一行:

printf("%d ", 16/2*2*2);

此文本替换完成后,编译器会检查表达式。这导致以下评估:

// 16/2 is evaluated first because '/' has the same precedence as '*',
// so the tie is broken by left-to-ride order:
printf("%d ", 8*2*2);

// Then each of the '*' operators is evaluated in turn:
printf("%d ", 16*2);
printf("%d ", 32);

通常建议通过在宏参数的每次使用周围和整个宏定义周围使用括号来防止运算符优先级改变宏中表达式的解释:

#define cube(x) ((x)*(x)*(x))

请注意,如果cube不是宏而是函数,结果会有所不同,因为函数在传递参数之前完全编译

int cube (int x)
{
   return x*x*x;
}
…
printf("%d ",16/cube(2)); // Prints 2.

脚注

1 实际上,文本被解析为预处理器标记,并且还可能发生一些其他语法事物。在很大程度上,宏观替换是文本替换,但可能会有一些复杂性。

答案 2 :(得分:3)

如果您使用-E进行gcc编译以查看预处理器输出

gcc -E demo.c > out.c

这可以帮助您下​​次

答案 3 :(得分:1)

因为立方体是一个宏,

16/cube(2)

通过预处理器评估

16/2*2*2

来到32。

如果需要宏(与函数相对),请将输入和输出括在括号中。 e.g。

#define cube(x) ((x)*(x)*(x))

但我真的在这里使用了一个功能。

答案 4 :(得分:0)

在使用宏的情况下,我们应该非常小心。它看起来像一个函数,但实际上它不是一个函数。在编译时,预处理器只是在第一次使用宏

时将宏扩展到任何位置
printf("%d ",cube(2)); expands into printf("%d",x*x*x); then it prints 8
printf("%d ",16+cube(2)); expands into  printf("%d",16+x*x*x); then it prints 24
printf("%d ",16/cube(2)); expands into printf("%d",16/x*x*x); but prints 32