以下代码的输出是什么,请帮助...... 我没有收到任何编译器错误
编译器如何评价这样的表达式?
#include <stdio.h>
int main()
{
int y = 3;
int z = (y = 30) + (y = 10) + (y = 20);
// `print z`
printf("%d\n", z);
// `print y`
printf("%d\n",y);
}
严格来说,该行为是 未定义:
6.5 表达方式 ... 2 如果一个标量对象上的侧效应相对于同一标量对象上的不同侧效应或使用同一标量对象的值计算而言是无序的,那么行为是未定义的。如果一个表达式的表达式有多个可允许的排序,如果这种未排序的侧效应发生在任何一个排序中,那么行为是未定义的。84)
84)本段将未定义的语句表达式,如i = ++i + 1; a[i++] = i;同时允许i = i + 1; a[i] = i;
C++也有类似的语言。
C语言并不强制对算术表达式进行从左到右的评价--每个算术表达式的 y=30
, y=10
和 y=20
子表达式可以按照任何顺序进行评估(并行架构可以对所有的子表达式进行评估)。同时). 这些表达式中的每一个都有一个 副作用 - 他们改变了 y
:
6.5.16 指派运算符 ... 3 赋值运算符在左操作数指定的对象中存储一个值。赋值表达式在赋值后有左操作数的值。111) 但不是一个lvalue。赋值表达式的类型是左操作数在lvalue转换后的类型。更新左操作数的存储值的副作用是在左操作数和右操作数的值计算后进行排序。操作数的计算是无序的。
111)允许实现读取对象来确定值,但不要求这样做,即使当对象具有volatile-qualified类型。
同上。
请注意,强调的部分只规定了在评估两个操作数后对侧效果进行排序--并没有说它会发生 马上 后。 y
可 每次任务完成后立即更新,也可能不更新。
"但是",我听到你说,"结果是......"。y = 10
是 10
无论 y
是否更新,那么存储在 z
做 60
不考虑其他所有的东西?"
这就是未定义行为的问题--一旦你的程序的任何部分未定义,整个程序就会未定义。 没有任何东西可以保证。 z
可 得值 60
. 可能会得到别的东西。
没有办法预测什么是价值的。y
应该在这最后,也。