请解释为什么Java和C为此代码提供不同的答案
public class Test { public static void main(String[] args) { int i = 10; i = i++; System.out.println("value of i is : " + i); } }
输出为: 10
当我在C
执行类似的代码时,输出为11
。
关于C
这是未定义的行为,因为您尝试在此行的同一序列点中多次修改同一个变量:
i = i++;
第6.5
节第2段中的 C99标准草案说:
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次 。 此外, 先前的值应该是只读的,以确定要存储的值 。
这在Java中得到了很好的定义,它没有与C
相同的序列点概念,并且Java语言规范( JLS ) 不遗余力地确保定义了这样的操作。 JLS第15.7节说:
在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已完全评估。 例如,如果左侧操作数包含对变量的赋值,而右侧操作数包含对该同一变量的引用,则引用生成的值将反映赋值首先发生的事实。 […]
第15.7.2
节说:
Java编程语言还保证在执行操作本身的任何部分之前 ,操作符的每个操作数(条件运算符&&,||和?:)除外似乎都被完全评估。
注意, C
没有指定评估顺序,主要是为编译器提供更好的优化选项 。 从标准草案第6.5
节第3段 :
运算符和操作数的分组由语法表示.74)除了稍后指定的(对于函数调用(),&&,||,?:和逗号运算符), 子表达式的评估顺序和顺序发生哪些副作用都是未指明的。
更新
如果您想要讨论Java和C之间在未定义行为方面的一些哲学差异,那么Undefined行为是 Java中 的设计决策和未定义行为 。
这是C
未定义行为 。 缺乏序列点 。
在Java中, i = i++;
post ++将在该步骤后增加值。 但是在将i++
分配给i++
的那一刻, i
仍然是10
所以你得到10
。 但在C中,这可能与Java不同。 如果在Java
代码中使用i=++i
,则会得到11.
Java和C是具有不同规则的不同语言。 在C中, 未指定评估表达式和应用副作用的确切顺序; 对于像i = i++
这样的表达式,不能保证在赋值发生之前应用++
运算符的副作用。 结果将根据平台,优化设置甚至周围的代码而有所不同。 行为未定义 ; 编译器可以以任何方式处理该情况,包括生成意外结果。
Java,OTOH确实指定了严格的评估顺序,并且立即应用了副作用,因此表达式是明确定义的。