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

fly*_*uzi 0 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);
}
Run Code Online (Sandbox Code Playgroud)

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

~ $ gcc a.c
~ $ ./a.out
a is 361, i is 19
Run Code Online (Sandbox Code Playgroud)

我想到了,我能想出的唯一解释是编译器对值进行了"延迟"评估(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);
}
Run Code Online (Sandbox Code Playgroud)

现在我在提示时输入17:

~ $ gcc a.c
~ $ ./a.out
17
a is 418, i is 19
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*eld 5

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

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