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++;
第2节中的C99 标准草案说:6.5
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。此外,应仅读取先验值以确定要存储的值。
这在 Java 中得到了很好的定义,它没有相同的序列点概念,C
Java 语言规范 ( JLS ) 竭尽全力确保定义了此类操作。JLS第15.7节说:
在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已被完全评估。例如,如果左侧操作数包含对变量的赋值,而右侧操作数包含对同一变量的引用,则引用产生的值将反映赋值首先发生的事实。[...]
和部分15.7.2
说:
Java 编程语言还保证运算符的每个操作数(条件运算符 &&、|| 和 ? : 除外)在执行操作本身的任何部分之前似乎都已被完全评估。
注意C
没有指定求值顺序,主要是给编译器更好的优化选项。从标准部分草案6.5
第 3 段:
运算符和操作数的分组由语法指示。74) 除稍后指定(对于函数调用 ()、&&、||、?: 和逗号运算符)外,子表达式的求值顺序和中的顺序发生哪些副作用都未指定。
更新
如果您想讨论 Java 和 C 之间关于未定义行为的一些哲学差异,您有未定义行为是设计决策和Java 中的未定义行为。
在 Java 中,i = i++;
post ++ 将在该步骤之后增加值。i++
但在分配给这里的那一刻i
,i
仍然是10
你得到的10
。但在 C 中,这可能与 Java 不同。如果你i=++i
在Java
代码中使用,你会得到11.
Java 和 C 是具有不同规则的不同语言。在 C 中,计算表达式和应用副作用的确切顺序是未指定的;对于像这样的表达式,不能保证在赋值之前会应用运算符i = i++
的副作用。++
结果会因平台、优化设置甚至周围的代码而异。行为未定义;编译器可以以它认为合适的任何方式处理这种情况,包括生成意外结果。
Java, OTOH 确实指定了严格的求值顺序,并且副作用会立即应用,因此表达式是明确定义的。