0

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

#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 规范中,它说操作数评估的顺序是undefined,所以我期望看到 22 * 19 或 19 * 14。但是,结果是 19 * 19:

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

我想了想,我能想到的唯一解释是编译器对(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

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

4

2 回答 2

5

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

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

于 2013-03-07T02:25:38.600 回答
3

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

在您的第二个示例中, scanf 使该优化变得不可能。编译器无法提前知道i的值是什么,并且执行您所期望的,这是标准未定义的。

于 2013-06-17T19:37:47.827 回答