#include<stdio.h>
#define CUBE(x) (x*x*x)
int main()
{
int a, b=3;
a = CUBE(++b);
printf("%d, %d\n", a, b);
return 0;
}
该代码返回值a=150
和b=6
。请解释一下。解释这个C程序的输出?
我认为,当它执行的a
值将被计算为a=4*5*6=120
但根据编译器是不正确的,所以请解释逻辑....
#include<stdio.h>
#define CUBE(x) (x*x*x)
int main()
{
int a, b=3;
a = CUBE(++b);
printf("%d, %d\n", a, b);
return 0;
}
该代码返回值a=150
和b=6
。请解释一下。解释这个C程序的输出?
我认为,当它执行的a
值将被计算为a=4*5*6=120
但根据编译器是不正确的,所以请解释逻辑....
有没有逻辑,这是不确定的行为,因为
++b * ++b * ++b;
修改并读取3次,没有交错序列点。
奖励:如果您尝试CUBE(1+2)
,您会看到另一个奇怪的行为。
除了什么Luchian格里戈里说(这也解释了为什么你看到这个怪异的行为),你应该注意到这个宏可怕:它可能会导致微妙,很难追踪下的错误,尤其是在与一个叫语句有副作用(如++b
),因为这会导致语句执行多次。
您应该从这次发现三条东西:
决不参考宏参数比宏一次。虽然这条规则有例外,但您应该将其视为绝对的。
尝试避免在可能的情况下调用带有包含副作用的语句的宏。
尝试到避免函数式的宏如果可能的话。改用内联函数。
它的undefined behavior在一个序列中多次改变相同的变量。而且因为这个原因,你将得到不同的编译器为你的代码的不同结果。
通过机会我也得到了同样的结果a = 150 and b = 6
与我的编译器。
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
您的宏表达a = CUBE(++b);
大片如
a = ++b * ++b * ++b;
而且b
是full expression.年底前改变更多然后一次。但我的编译器如何在低级别转换此表达式(可能是您的编译器做类似的操作,您可以尝试使用相同的技术)。为此,我使用-S
选项编译了源代码C,并获得了汇编代码。
gcc x.c -S
您将获得x.s
文件。
我显示部分有用的汇编代码(阅读评论)
因为你想知道如何做150
输出,这就是为什么我加入我的答案
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -8(%rbp) // b = 3
addl $1, -8(%rbp) // b = 4
addl $1, -8(%rbp) // b = 5
movl -8(%rbp), %eax // eax = b
imull -8(%rbp), %eax // 5*5 = 25
addl $1, -8(%rbp) // 6 `b` become 6 and
imull -8(%rbp), %eax // 6 * 25 = 150
movl %eax, -4(%rbp) // 150 assign to `a` become 150
movl $.LC0, %eax // printf function stuff...
movl -8(%rbp), %edx
movl -4(%rbp), %ecx
movl %ecx, %esi
movq %rax, %rdi
在检查这汇编代码我可以理解它评估表达式,如 a = 5 * 5 * 6
因此a
变成150
,并在三个增量后b
变为6
。
虽然不同的编译器产生不同的结果,但我认为,150
驾驶室只评估了此序列b=3
和您使用什么编译您在5*5*6
体现在哪里?如果我使用gcc 4.2.1,我得到结果:a = 120,b = 6 – 2013-03-15 17:50:17
@Magnus:任何结果都是可能的。你可以得到'a = 120,b = 6'或者你可以得到'土豆'。这是未定义的行为。 – 2013-03-15 18:02:01