赋值运算符中的序列点

Sequence point within assignment operators

让我们以特定的复合赋值运算符^=为例。 This Whosebug page 表示在 ^= 求值后可能尚未完成对左操作数的修改,因此使代码 a ^= b ^= a ^= b 未定义行为。但事实似乎并非如此。该标准在 5.17 [expr.ass] 中说

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

这句话有两个重点。 1) 主题 assignment 指的是什么?在我看来,它只是指左操作数的修改。 2)赋值表达式的取值指的是什么? cppreference 表示它指的是返回对 修改后的 对象的引用(强调我的)。

作为结论,左操作数应该在^=的评估之后已经被修改,这与(大多数)人的想法相矛盾。我在这里遗漏了什么吗?

你link来了一道C题。但是,这无关紧要,因为 C 和 C++ 是不同的语言。

此外,从 C11 和 C++11 开始,序列点不再存在;取而代之的是 前序未序不确定序的关系存在。

在那句话中:

  • 赋值表示写入a.
  • 的内存位置
  • value computation of an expression 表示计算该表达式的值。 (示例 - 2 + 2 的值为 4,值计算是确定 4 为该值的过程。

此处有两个值计算:a ^ ba =(该结果)。

在引用的文本中,对于 a = a ^ b,事情必须按以下顺序发生:

  1. ab中取值(任意顺序),并确定存储结果的内存位置(右操作数和左操作数的值计算,分别)

  2. 将结果存入a(赋值)。涉及a ^ b的值计算,引用中没有提到,但显然结果必须在存储之前计算

  3. 执行赋值表达式的值计算。这意味着放弃存储在 a 中的值,以供周围的表达式使用(值计算)。

你说得对,2 和 3 看起来 "backwards" 与你在纸上做事的顺序相比。但请记住,一般来说,yx = y 的值不同。赋值表达式的值与存储在 x 中的值相同。 (示例:int x; double y = (x = 6.5); - 那么 y 就是 6,而不是 6.5)。所以我们可以通过将结果存储在 a 中然后提供 a 作为结果来做到这一点。