【问题标题】:Can you assign the value of one union member to another?您可以将一个工会成员的价值分配给另一个工会成员吗?
【发布时间】:2014-02-25 18:21:50
【问题描述】:

考虑以下代码sn-p:

union
{
   int a;
   float b;
};

a = /* ... */;

b = a;               // is this UB?
b = b + something;

将一个工会成员分配给另一个工会成员是否有效?

【问题讨论】:

  • 我把帖子删减了一点,希望没问题。随时恢复。
  • 在 C 中,答案是这是明确定义的,因为在 C++ it is not as clear 中允许使用类型双关语 since C89。所以这里的问题是b = a 只是考虑让b 活跃?否则按照1.9 p15 进行自我分配应该没问题。
  • 是的,你是对的。在 C++ 中,类型双关语似乎是模棱两可的。删除了我的答案。感谢您指出。
  • 我想知道this answer 是否在某种程度上是相关的。此外,如果您考虑用户定义类型的联合,那将会很有趣。
  • @KerrekSB this conversation on WG21 UB study group mailing list 似乎表明这确实非常模糊。我必须考虑,但我认为答案是未指定 :-(

标签: c++ memory language-lawyer unions


【解决方案1】:

不幸的是,我认为这个问题的答案是 C++ 中未指定联合操作,尽管自分配完全没问题。

自赋值是明确定义的行为,如果我们查看草案 C++ 标准部分 1.9程序执行 段落 15 有以下示例:

void f(int, int);
void g(int i, int* v) {
    i = v[i++]; // the behavior is undefined
    i = 7, i++, i++; // i becomes 9

    i = i++ + 1; // the behavior is undefined
    i = i + 1; // the value of i is incremented

    f(i = -1, i = -1); // the behavior is undefined
}

i = i + 1 示例中介绍了自分配。

这里的问题是unlike C89 forward 支持C++ it is not clear 中的类型双关语。我们只知道:

在一个联合中,任何时候最多可以有一个非静态数据成员处于活动状态

但是由于WG21 UB study group mailing list 中的讨论表明这个概念还没有被很好地理解,我们有以下 cmets:

虽然标准使用术语“活动字段”,但并未对其进行定义

并指出这个非规范性注释:

注意:通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员。 ——尾注

所以我们不得不怀疑:

b = a;

是否让b 成为活跃成员?我不知道,也没有办法用任何当前版本的标准草案来证明这一点。

尽管实际上大多数现代编译器(例如 gcc)都支持 C++ 中的类型双关语,这意味着活动成员的整个概念都被绕过了。

【讨论】:

  • 在我看来,如果a = b; 的定义不清楚,那么auto x = b; a = x; 也不清楚。但显然后者一定没问题。标准规定,在表达式a = b 中的实际赋值之前,读取右侧的顺序。因此,在这两种情况下,我们都有一个序列,我在a = b 中看不到任何其他更重要的内容(至少在我可以在规范中指出的内容中。当然它对我来说“看起来更重要”,但主题感觉不算数)。
  • @JohannesSchaub-litb 你是不同意这个结论还是只是我懒得提自我分配是明确定义的?
  • @ShafikYaghmour 我在这里看不到任何类型的双关语; b = a; 请求读取aint 值,转换为float,并将结果存储在b 中。问题是它是否由于ab 的存储重叠而未定义。 “类型双关”与别名相同,意思是通过将一个值的表示解释为不同类型的值的表示来试图绕过类型系统;但在这种情况下不会发生这种情况。
【解决方案2】:

我希望除非源变量和目标变量是同一类型,否则这样的事情将是 C 中的未定义行为,我认为没有理由期望 C++ 以不同方式处理它。给定long long *x,*y;,一些编译器可能会通过生成代码来读取所有 *y、计算结果并将其存储到 *x 来处理类似 *x = *y >>8; 的语句,但编译器可能完全合法地编写复制 *y 部分的代码到 *x 单独。该标准明确指出,如果 *x 和 *y 是指向同一类型的同一对象的指针,编译器必须确保值的任何部分都不会被覆盖而在计算中仍需要该部分 ,但编译器不需要在其他情况下处理别名。

【讨论】:

    猜你喜欢
    • 2017-06-13
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 2017-10-29
    • 1970-01-01
    相关资源
    最近更新 更多