前提

表达式有两种功能:

表达式中的副作用何时生效以及运算对象的求值顺序,会影响到表达式的值。比如:

int a = 4, b;
b = a++ + a;

因此下面讲述两个概念:


顺序点

在C、C++等允许表达式有副作用的语言中,通常都规定了顺序点,顺序点就是表达式中的副作用的最晚生效时刻。在程序执行中,存在一系列的顺序点,一旦执行到一个顺序点,此前的副作用都必须生效。但是在顺序点之间并没有任何保证。
C/C++明确定义了顺序点的概念。顺序点位于:

假设时刻ti和ti+1是前后相继的两个顺序点,到了ti+1,必须实现ti之后发生的所有副作用。当然也可以不等到时刻ti+1,完全可以选择在时段 [ti, ti+1] 之间的任何时刻实现在此期间出现的副作用。


求值顺序

(a + b) * (c + d)
“*”的两个运算对象哪个先算?
fun(a++, b, a+5)
fun及其三个参数按什么顺序计算?
对第一个表达式,采用任何计算顺序都没关系,因为其中的子表达式都是引用透明的。第二个例子里的实参表达式出现了副作用,计算顺序就非常重要了。在计算第二个表达式时,首先按照某种顺序算fun、a++、b和a+5,之后是顺序点,而后进入函数执行。
还要注意顺序点的问题:即使某一边的表达式先算了,其副作用也可能没有反映到内存,因此对另一边的计算没有影响。
Java明确规定求值顺序是从左到右。