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
。
答案 0 :(得分:14)
关于C
这是undefined behavior,因为您尝试在此行的同一sequence point内多次修改同一个变量:
i = i++;
6.5
第2段中的draft C99 standard说:
在上一个和下一个序列点之间,对象应具有其存储值 通过表达式的评估,最多修改一次。此外,先前的值 应该只读以确定要存储的值。
这在Java中得到了很好的定义,它没有C
所做的相同的序列点概念,并且Java语言规范( JLS )不再适用确保定义此类操作。 JLS的15.7部分说:
在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已完全评估。例如,如果左侧操作数包含对a的赋值变量和右侧操作数包含对同一变量的引用,然后引用生成的值将反映赋值首先发生的事实。 [...]
和第15.7.2
部分说:
Java编程语言还保证在执行操作本身的任何部分之前,运算符的每个操作数(条件运算符&&,||和?:) 除了完全评估之外。 强>
请注意,C
未指定评估顺序,主要是为了给编译器better options for optimization。来自标准草案部分6.5
第3段:
运算符和操作数的分组由语法表示.74)除非另有说明 稍后(对于函数调用(),&&,||,?:和逗号运算符),子表达式的评估顺序和副作用发生的顺序都是未指定的。强>
更新
如果您想讨论Java和C之间在未定义行为方面的一些哲学差异,那么您需要Undefined behavior is a design decision和Undefined behaviour in Java。
答案 1 :(得分:5)
这是C
中的Undefined behaviour。缺乏sequence point。
答案 2 :(得分:0)
在Java中,i = i++;
post ++将在该步骤后增加值。但是,在将i++
分配给i
时,i
仍为10
,因此您获得了10
。但在C中,这可能与Java不同。如果您在i=++i
代码中使用Java
,则会获得11.
答案 3 :(得分:0)
Java和C是具有不同规则的不同语言。在C中,评估表达式和应用副作用的确切顺序是未指定;对于i = i++
这样的表达式,无法保证在作业发生之前应用++
运算符的副作用。结果将根据平台,优化设置,甚至周围的代码而有所不同。行为未定义;编译器可以按照它认为合适的方式处理这种情况,包括产生意外结果。
Java,OTOH确实指定了严格的评估顺序,并且立即应用了副作用,因此表达式定义明确。