C ++联盟成员未初始化

时间:2012-10-12 01:45:24

标签: c++ initialization unions

当我发现一些奇怪的东西时,我才刚开始接触工会

如果我运行此程序

    #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;
    }

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

    #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,因为y.c ='B'用其ASCII值(66)替换65。      任何人都可以解释第一个案例吗?

7 个答案:

答案 0 :(得分:2)

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

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

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

  

在联合中,最多一个数据成员可以随时处于活动状态,也就是说,任何时候最多一个数据成员的值都可以存储在一个联合中。

如果您想要进行此类重叠活动,我想您可能需要查看reinterpret_cast


就第一个内容实际发生的情况而言,数字输出的十六进制值:

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

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

通过在该点之前放入y.x=65行,它将设置所有四个字节,并将这三个备用字节设置为零。因此,当您在以下赋值中设置单个字节时,它们将保持为零。

答案 1 :(得分:1)

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

初始化字符部分仅修改提供int的数据类型中的一个字节。假设32位int,这意味着3个字节仍未被初始化...因此垃圾。

以下是你的联盟的内存使用情况:

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

设置x时,设置一个整数,以便初始化所有剩余字节。设置c时,只修改单个字节。

答案 2 :(得分:1)

  y.c='B';
 cout<<y.x;

这有未定义的行为。在任何给定时间,union只包含其中一个成员。如果int成员实际包含char成员,则无法尝试阅读{{1}}成员。由于未定义此行为,因此允许编译器使用代码执行所需操作。

答案 3 :(得分:1)

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

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

首先设置联盟中最大的成员,或者执行以下操作:

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

用零填充整个联盟。

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

变量y是union类型,y的长度是4个字节。例如,y的内存布局是这样的:

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

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

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