如果让我说,C 语言没有规定运算的实际顺序,所以不能保证赋值是在加法左边求值以后进行的。虽然在这里,这一点并没有影响最后的值,但是根据ANSI C 标准,很遗憾,这仍然是未定义的,参考下面引用的资料:
4.5 我可否用括号来强制执行我所需要的计算顺序?
一般来讲, 不行。运算符优先级和括弧只能赋予表达是计算部分的顺序. 在如下的代码中
f() + g() * h()
尽管我们知道乘法运算在加法之前, 但这并不能说明这三个函数哪个会被首先调用。
如果你需要确保子表达式的计算顺序, 你可能需要使用明确的临时变量和独立的语句。
参考资料: [K&R1, Sec. 2.12 p. 49, Sec. A.7 p]; [K&R2, Sec. 2.12 pp. 52-3, Sec. A.7 p. 200.]。
4.7 我怎样才能理解复杂表达式?``序列点" 是什么?
序列点是一个时间点(在整个表达式全部计算完毕之后或在 ||、 &&、 ? : 或逗号 运算符处, 或在函数调用之前), 此刻尘埃落定, 所有的副作用都已确保结束。 ANSI/ISO C 标准这样描述:
在上一个和下一个序列点之间, 一个对象所保存的值至多只能被表达式的计算修改一次。而且前一个值只能用于决定将要保存的值。
第二句话比较费解。它说在一个表达式中如果某个对象需要写入, 则在同一表达式中对该对象的访问应该只局限于直接用于计算将要写入的值。这条规则有效地限制了只有能确保在修改之前才访问变量的表达式为合法。例如 i = i+1 合法, 而 a[i] = i++ 则非法 (参见问题 3.1)。
参见下边的问题 3.8。
参考资料: [ISO, Sec. 5.1.2.3, Sec. 6.3, Sec. 6.6, Annex C]; [Rationale, Sec. 2.1.2.3]; [H&S, Sec. 7.12.1 pp. 228-9]。
注意4.7这一条,“而且前一个值只能用于决定将要保存的值。 “,显然你的表达式违反了这一条——x的第一次引用的值用来决定了整个表达式的值,而不是x的新值,x的新值由y决定。所以你的表达式是未定义的。