1

当我发现一些奇怪的东西时,我刚刚开始与工会一起探索

如果我运行这个程序

    #include <iostream>
    using namespace std;
    union myun{
    public:
    int x;
    char c;
    };

    int main()
    {
     myun y;
     //y.x=65;
      y.c='B';
     cout<<y.x;
    }

输出是一些垃圾值,如果改变 yc 的值不会改变接下来我做了这个

    #include <iostream>
    using namespace std;
    union myun{
    public:
    int x;
    char c;

    };
     int main()
     {
      myun y;
      y.x=65;
      y.c='B';
      cout<<y.x;
     }

输出如预期的那样为 66,因为 yc='B' 将 65 替换为其 ASCII 值 (66)。谁能解释第一种情况?

4

7 回答 7

2

从不是最后一个写入的联合成员中读取实际上是未定义的行为。

如果联合中的项目是布局兼容的(如标准中定义的),则可以执行此操作,但这里的情况并非如此intchar更正确地说,如果这两种类型具有相似的位宽,则可能是这种情况,但那是通常情况并非如此)。

从 C++03 标准(现在被 C++11 取代但仍然相关):

在一个联合中,任何时候最多可以有一个数据成员处于活动状态,即任何时候最多可以有一个数据成员的值存储在一个联合中。

我想你可能想看看reinterpret_cast你是否想做这种叠加活动。


就第一个幕后实际发生的事情而言,数字输出的十六进制值:

-1218142398 (signed) -> 3076824898 (unsigned) -> B7649F42 (hex)
                                                       ==
                                                       ^^
                                                       ||
                                       0x42 is 'B' ----++

应该提供线索。y.c='B'仅设置该结构的单个字节而其他三个字节(在我的情况下)则不确定。

通过在y.x=65该点之前插入一行,它设置了所有四个字节,而这三个备用字节设置为零。因此,当您在以下分配中设置单个字节时,它们保持为零。

于 2012-10-12T01:49:05.377 回答
1

好吧,当你展示你对第二种情况的理解时,你有点解释了第一种情况。

初始化字符部分只会修改提供int. 假设 32 位 int,这意味着 3 个字节仍未初始化......因此是垃圾。

这是您的工会的内存使用情况:

              byte
           0  1  2  3
         +------------
myun::x  | X  X  X  X
myun::c  | X  -  -  -

当你设置时x,你设置一个整数,所以所有剩余的字节都被初始化。当你设置 时c,你只修改一个字节。

于 2012-10-12T01:50:41.473 回答
1
  y.c='B';
 cout<<y.x;

这具有未定义的行为。在任何给定时间,联合仅包含其成员之一。int如果它实际上包含该成员,则您不能尝试读取该char成员。因为没有定义这种行为,所以允许编译器对代码做它想做的事情。

于 2012-10-12T01:51:59.773 回答
1

因为sizeof(int) != sizeof(char).

也就是说,一个整数和一个字符占用的内存量是不同的(在现在的普通计算机中,int 是 4 个字节,char 是 1 个字节)。工会的规模与其最大的成员一样大。因此,当您设置 char 时,您只设置了 1 个字节的内存 - 其他 3 个字节只是随机垃圾。

要么首先设置工会的最大成员,要么执行以下操作:

memset(&y, 0, sizeof(y));

用零填充整个联合。

于 2012-10-12T01:52:17.203 回答
1

在联合中,分配的内存等于最大成员的大小,在您的情况下是 int ,即在 16 位编译器的情况下为 2 个字节。所有成员使用相同的内存空间来存储他们的数据,因此实际上一次只能存储一种类型的成员。

当您将值“B”分配给 char 成员时,它在 1 字节的内存空间中存储了 66。然后,您尝试输出 int 成员的值,但该成员尝试通过从内存的 2 个字节读取值来计算值,因此您得到了一个垃圾值。

于 2012-10-12T01:53:35.183 回答
0

变量y是联合类型,y的长度是四个字节。比如y的内存布局是这样的:

---------------------------------
| byte1 | byte2 | byte3 | byte4 |
---------------------------------

1)在第一个程序中,这句话 y.c='B';只是设置了byte1,但是byte2、byte3、byte4是栈中的随机值。

2)在第二个程序中,句子yx=65;设置 byte1 为 65 , byte2, byte3, byte4 为零。然后,句子y.c='B';将 byte1 设置为 'B' 的整数 ASCII 值,因此输出为 66。

于 2012-10-12T01:58:24.363 回答
0

POD 类型的局部变量(更具体地说,堆栈上的变量,即具有“自动”存储类)在声明时不会初始化为任何内容,因此 3 个字节(或 64 位系统上的 7 个字节)不受您的分配y.c将包含随机垃圾。

另请注意,受分配 to 影响的特定字节y.c取决于 CPU 的字节顺序,因此即使您y.x在分配 to 之前进行初始化,此代码在不同系统上的行为也会有所不同y.c

于 2012-10-12T01:56:43.303 回答