0

以下代码的输出是 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));
}
4

5 回答 5

4

最后一个printf被翻译成:

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

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

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

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

于 2012-12-31T12:11:03.100 回答
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实际上,文本被解析为预处理器标记,并且可能会出现其他一些语法问题。在很大程度上,宏替换是文本替换,但可能会有一些复杂性。

于 2012-12-31T12:11:01.667 回答
3

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

gcc -E demo.c > out.c

下次可以帮到你

于 2012-12-31T12:14:03.963 回答
1

因为立方体是一个宏,

16/cube(2)

通过预处理器评估为

16/2*2*2

达到32。

如果您需要宏(而不是函数),请将输入和输出括在括号中。例如

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

但我真的会在这里使用一个函数。

于 2012-12-31T12:11:06.550 回答
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
于 2012-12-31T15:22:06.620 回答