【问题标题】:C/C++ unions and undefined behaviourC/C++ 联合和未定义的行为
【发布时间】:2015-10-22 21:31:48
【问题描述】:

是以下未定义的行为吗?

 union {
   int foo;
   float bar;
 } baz;

 baz.foo = 3.14 * baz.bar;

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

【问题讨论】:

  • 评估是无序的,但不是副作用,在 C++11 中是有序的。
  • 您想要哪种语言的答案?
  • @AlanStokes:C 和 C++,标记为:D
  • 请明确您想要 C 还是 C++ 答案。不是两者都有,否则这个问题太宽泛了。
  • @Walter 那么为什么 SO 允许两个标签呢?

标签: c++ c language-lawyer undefined-behavior unions


【解决方案1】:

免责声明:此答案针对 C++。

您正在访问一个生命周期尚未开始的对象 - baz.bar - 这会通过 [basic.life]/(6.1) 引发 UB。

假设bar 已被激活(例如通过初始化它),您的代码就可以了;在分配之前,foo 不需要处于活动状态,因为没有执行依赖于其值的操作,并且在此期间,通过重用内存并有效地初始化它来更改活动成员。目前的规则并不清楚后者;见CWG #1116。但是,现状是这样的分配确实将目标成员设置为活动(=alive)。

请注意,赋值是在操作数的值计算之后排序的(即保证发生) - 请参阅 [expr.ass]/1。

【讨论】:

  • @Barry 表示后者。参见 CWG 556。
  • 目前我没有 C++ 标准副本来检查更多细节,但我对你的解释有些怀疑。
  • @Columbo 但是那很奇怪吧? u.a = u.b 未定义,但 u.a = B(u.b) 可以吗?
  • @Barry 这很奇怪,但这是 AFAICS 措辞的意图(“不是关于别名的一般性陈述,而是描述了分配值的来源是重叠的存储的情况目标对象的存储”)。目标对象是float 类型的临时对象,但该临时对象的存储肯定不会与baz.foos 重叠。再说一次,也许委员会在他们的说明中措辞不够准确,他们实际上的意思是 u.a=f(u.b) 没有定义。不管怎样,生命周期规则都是一团糟。
  • 该行为肯定是在 C 中定义的,假设 baz.bar 已经被初始化并且 baz.foo 没有随后被写入。鉴于 2011 版标准中的 C/C++ 协调工作,我会非常惊讶地发现相同的代码在 C++ 中具有未定义的行为。
【解决方案2】:

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

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

C11:6.5 表达式:

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

表达式

 baz.foo = 3.14 * baz.bar;  

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

6.5.16(p3):

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

【讨论】:

  • 这不太正确:printf("%d", i + i++); 具有未定义的行为。
  • 同一内存位置的无序读写是UB,就像两次无序写入一样。
  • @melpomene,“未排序”是 C2011 标准中的定义术语。对于这个场所来说,一个完整的定义可能不合适,但我鼓励您阅读标准本身对它的描述,以及关于“sequenced before”关系的内容。
  • @melpomene;阅读this 了解关于sequence before 和unsequenced 的所有信息。从here下载n1570 pdf。
  • @hacks,您省略了提及与此问题相关的标准的关键规定:“更新左操作数 [赋值运算符] 的存储值的副作用排序在左右操作数的值计算”(来自 C11 6.5.16/3)。如果没有该条款或其他具有相同效果的条款,您引用的条款将认为该行为是未定义。
猜你喜欢
  • 2019-08-12
  • 2016-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
相关资源
最近更新 更多