C/C++ 联合和未定义的行为

Vro*_*del 8 c c++ undefined-behavior unions language-lawyer

以下是未定义的行为吗?

 union {
   int foo;
   float bar;
 } baz;

 baz.foo = 3.14 * baz.bar;
Run Code Online (Sandbox Code Playgroud)

我记得在两个序列点之间从同一底层内存进行写入和读取是UB,但我不确定。

hac*_*cks 6

我记得在两个序列点之间从同一底层内存进行写入和读取是UB,但我不确定。

读取和写入同一表达式中的同一内存位置不会调用未定义的行为,除非该位置在两个序列点之间修改多次,或者副作用相对于使用同一位置处的值的值计算而言是无序的。

C11:6.5 表达式:

如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则行为是未定义的。[...]

表达方式

 baz.foo = 3.14 * baz.bar;  
Run Code Online (Sandbox Code Playgroud)

如果bar在之前初始化,则具有明确定义的行为。原因是 的副作用baz.foo是相对于对象baz.foo和的值计算来排序的baz.bar

C11:6.5.16/3 赋值运算符:

[...]更新左操作数的存储值的副作用是在左操作数和右操作数的值计算之后排序的。操作数的计算是无序的。

  • @melpomene,“未测序”是 C2011 标准中定义的术语。对于这个场所来说,完整的定义可能太大了,但我鼓励您阅读标准本身关于它以及“之前排序”关系的内容。 (3认同)
  • @melpomene;阅读[此](http://stackoverflow.com/a/31083924/2455888)以了解有关*之前的序列*和*未排序的*的所有信息。从[此处](http://www.compsci.hunter.cuny.edu/~sweiss/resources/c11standard.pdf)下载n1570 pdf。 (3认同)
  • @haccks,您省略了与此问题相关的标准的关键规定:“更新左操作数[赋值运算符]的存储值的副作用是在左操作数和右操作数的值计算之后进行排序的操作数”(来自 C11 6.5.16/3)。如果没有该规定或具有相同效果的其他规定,您引用的规定将认为该行为*是*未定义的。 (2认同)