是否赋值 x=1;根据 C17 始终是未定义的行为?

Is assignment x=1; always an undefined behaviour according to C17?

我正在查看 C17,N2176 的最终草案。在这里,我关心什么样的带有副作用的表达式会导致它的行为未定义。

在标准的第 6.5 节中,第 2 段以:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

据我了解,表达式 x=1 的求值既会产生一个值,也会引发副作用,改变 x 指定的对象的值。决定因素将是副作用是否以与使用 x 指定的对象值的值计算相关的任何方式排序。

6.5.16节赋值运算符的描述中有这样一句话:

The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

这不能解决整个赋值的值计算顺序和赋值的副作用。

另外,再说一句:

An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

指定最终值应该是什么,但不要求任何排序。而且我没有看到任何其他文本提到关于副作用和价值的排序。

我知道当写成一个完整的语句时 x=1;赋值的值没有被使用。但是,该标准表示该值已被丢弃。这意味着就好像先评估值然后丢弃,因此仍应触发未定义的行为。

是否有标准的任何其他部分使此语句行为不是未定义的?

赋值表达式的值不是对赋值对象的使用。这是因为 x = 1 的值,例如 y = x = 1,不是通过 x 的左值转换获得的,而是赋值表达式的值计算,根据 C 2018 6.5.16 3 :

… An assignment expression has the value of the left operand after the assignment,…

它进一步说:

… The type of an assignment expression is the type the left operand would have after lvalue conversion…

这是关于类型,而不是值,但是它使用虚拟语气“would have”表明“左值转换”是虚构的;它实际上并没有发生。所以赋值表达式不是通过读取左操作数来获取它的值;它的值仅仅是操作的结果。

那里有一个脚注 (115) 说:

The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.

这告诉我们,左操作数实际上可以用来计算赋值表达式的值。但是,这是声明它可以通过这样做来实现,而不是声明这是 C 计算模型中赋值表达式语义的一部分。