以下链式分配是否会导致未定义的行为?

Does the following chained assignment cause Undefined behavior?

以下代码是否调用了 C 中的未定义行为?

int a = 1, b = 2;
a = b = (a + 1);

我知道以下调用 UB:

a = b = a++;

原因是它违反了标准中的以下条款:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.

但是,第一个片段并不违反此条款。一位同事说 a = b = a+1 可以表示

a = a + 1;
b = a + 1;

b = a + 1;
a = b;

我认为由于=的"right-to-left"结合性,它总是意味着a = (b = (a+1)),而不是

a = a + 1;
b = a + 1;

不过我不是很肯定。是UB吗?

恕我直言,a = b = a+1 定义明确。

这里。您没有 更改 a 的值,只是在 a+1.

的情况下使用它

明确地说,根据=运算符的"right-to-left" associativity,你可以将上面的分解为,

b = a + 1;  //a does not change here, only the value is used.
a = b;
a = a++;

不同
a = a+1;

在第二种情况下,您没有通过执行 a+1 来修改 a 的值,而在第一种情况下,a 的值正在更改,这将导致未定义的行为.

a = b = a + 1; 等同于:

b = a + 1;
a = b;

您没有在右侧更改左侧的值,因此定义明确。

这是 C99 的完整序列点列表(改编自 C99,附件 C):

  • 在函数调用期间,在计算参数之后和执行函数体的任何部分之前;
  • 在以下运算符的第一个操作数的末尾:&&||?:,
  • 在完整声明符的末尾;
  • 在完整表达式的末尾(初始值设定项、表达式语句中的表达式、return 语句中的表达式、for 语句中的每个表达式,或控制ifswitchwhiledo 语句的表达式);
  • 紧接在库函数 returns 之前;
  • 在与每个格式化的 input/output 函数转换说明符关联的操作之后;
  • 紧接在每次调用比较函数之前和之后;以及在对比较函数的任何调用与作为参数传递给该调用的对象的任何移动之间(指 bsearch()qsort().

从这个角度考虑您的代码:

int a = 1, b = 2;
a = b = (a + 1);

有序列点

  1. a = 1(完整声明符)之后
  2. b = 2 之后(完整声明符)
  3. 在第二个语句的末尾。 (完整表达)

整个a = b = (a + 1)是一个单一的表达式语句,不包含内部序列点。但是,它并不违反禁止在序列点之间对其值修改一次以上的对象:ab 在整个语句中每个被修改一次。