C操作数评估顺序的意外行为

时间:2013-03-07 02:22:15

标签: c evaluation operands

所以只是为了好玩,我有这段代码:

#include <stdio.h>
main()
{
 int i;
 int a;
 i = 17;
 //scanf("%d", &i);
 a = (i+=5) * (i-=3);
 printf("a is %d, i is %d\n", a, i);
}

在C规范中,它表示操作数评估的顺序是未定义,所以我期望看到22 * 19或19 * 14.但是,结果是19 * 19:< / p>

~ $ gcc a.c
~ $ ./a.out
a is 361, i is 19

我想到了这一点,我能想出的唯一解释是编译器做了“延迟”#39;评估(i+=5)的值,它认为(i+=5)的值只是i的值。同样适用于(i-=3)

但是,如果我取消注释scanf()

#include <stdio.h>
main()
{
 int i;
 int a;
 i = 17;
 scanf("%d", &i);
 a = (i+=5) * (i-=3);
 printf("a is %d, i is %d\n", a, i);
}

现在我在提示符下输入17:

~ $ gcc a.c
~ $ ./a.out
17
a is 418, i is 19

为什么它表现出不同的行为?

2 个答案:

答案 0 :(得分:5)

未定义的行为。 C标准表示不允许在两个序列点之间多次修改同一个对象(在这种情况下为i)(在这种情况下,语句之前和之后的分号)。

未定义的行为意味着任何都可能发生。它似乎可以正常工作。它可以给出错误的答案。它可能会使您的流程崩溃。它可以擦除你的硬盘。或者它甚至可以让您的CPU着火。根据语言标准,这些都是允许的行为。

答案 1 :(得分:3)

可能主要区别在于,在第一种情况下, i 可以在整个生命周期内进行预测,因此优化器会预先计算它并用常量值替换变量。

在第二个示例中,scanf无法进行优化。编译器无法事先知道 i 的值是什么,并且符合您的预期,这是标准未定义的。