【问题标题】:Why does my union not show the correct values?为什么我的工会没有显示正确的值?
【发布时间】:2010-05-19 19:06:01
【问题描述】:
union
{ int i;
  bool b;
} x;

x.i = 20000;
x.b = true;
cout << x.i;

打印出19969,为什么打印不出20000?

【问题讨论】:

    标签: c unions


    【解决方案1】:

    union 不是struct。在union 中,所有数据都占用相同的空间,并且可以通过其字段名称将其视为不同的类型。当您将true 分配给x.b 时,您将覆盖20000 的低位。

    更具体地说:

    20000 二进制:100111000100000

    二进制19969:100111000000001

    这里发生的情况是,您在 200000 的 8 个低位中放入了一个单字节值 1 (00000001)。

    如果使用struct 而不是union,则intbool 将有空间,而不仅仅是int,您将看到预期的结果。

    【讨论】:

      【解决方案2】:

      在联合中,所有数据成员都从同一个内存位置开始。在您的示例中,您一次只能真正使用一个数据成员。但是,此功能可用于一些巧妙的技巧,例如以多种方式公开相同的数据:

      union Vector3
      {
        int v[3];
        struct
        {
          int x, y, z;
        };
      };
      

      这允许您通过名称(x、y 和 z)或作为数组 (v) 访问三个整数。

      【讨论】:

      • ...或者它可能无论如何。再说一次,它可能会在结构中的 ints 之间插入填充,在这种情况下,v[1]v[2] 将不会像预期的那样对应于 yz
      • 我不知道有一个编译器会在相同类型的两个数据成员之间放置填充。当连续的数据成员大小不同时出现填充,例如一个字符后跟一个短字符(很可能会在两者之间填充一个额外的字符)。也就是说,结构可能会被填充,以便它的总大小是字对齐的,所以如果 x、y 和 z 都是一个字节,它可能会被填充为 x、y、z、p 或 p、x, y, z(这确实会打破我的例子)。
      • 请注意,C 和 C++ 都没有匿名结构。因此,您需要为 struct 对象取一个类似 } vs; 的名称。或者尽可能依赖编译器扩展。
      【解决方案3】:

      工会在任何给定时间仅存储 一个 成员。要获得定义的结果,您只能读取上次写入 联合的同一成员 来自 联合。否则(就像你在这里)官方给出的只是未定义的结果。

      有时联合体被有意用于类型双关语(例如,查看构成浮点数的字节)。在这种情况下,由你来理解你得到的东西。这种语言试图给你一个战斗的机会,但它并不能真正保证多少。

      【讨论】:

      • 我不认为你在这里所说的任何事情实际上是不正确的,但我确实对使用“未定义”这个词有异议。 “未定义”是当您从未初始化的内存中读取时;当你有四个字节并覆盖其中一个时,你应该确切地知道你将拥有什么(认为一旦你投射它可能看起来很奇怪)。
      • @danben,你甚至不知道你正在覆盖一个字节。布尔值的写入可能会覆盖 int 的某些随机部分,当您稍后读取 int 而不随后分配给它时,您可能会导致 cpu 异常或类似情况(C 和 C++ 都允许这样的事情)。行为真的是不确定的,任何事情都可能发生。
      • 我相信根据标准,这种特定行为是实现定义的。
      • @danben:这取决于您采用的标准。 C89/90 使其行为未定义。在 C99 中,写入一个会导致另一个未指定值,但不允许在另一个中创建陷阱表示。在 C++ 中,这样做是隐式未定义的(即,没有定义任何行为,所以这样做会给出未定义的行为)。但在任何情况下都没有定义实现(这将需要实现来记录发生的事情,这将是困难且几乎毫无意义的)。
      • @danben:从 n1256 开始,行为未指定:J.1/1,“除了最后一个存储到 (6.2.6.1) 中的联合成员的值。”
      【解决方案4】:

      C 中的联合便于不同变量共享内存空间。
      因此,当您在 union 中更改任何变量时,所有其他变量的值也会受到影响。

      【讨论】:

        猜你喜欢
        • 2021-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多