简体   繁体   English

C ++ Union成员未初始化

[英]C++ Union member not initialized

I was just beginning my quest with unions when I found something weird 当我发现一些奇怪的东西时,我才刚刚开始寻找工会

If I run this program 如果我运行此程序

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

The output was some garbage value which doesnt change if change the value of yc Next I did this 输出是一些垃圾值,如果更改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;
     }

The output was as expected to be 66 because yc='B' replaces the 65 by its ASCII value(66). 预期输出为66,因为yc ='B'用其ASCII值(66)替换了65。 Can anyone explain the first case? 谁能解释第一种情况?

It's actually undefined behaviour to read from a union member that wasn't the last one written to. 读取不是最后一个写入的工会成员的行为实际上是未定义的。

You can do this if the items within the union are layout-compatible (as defined in the standard) but that's not the case here with an int and char (more correctly, it could be the case if those two types had similar bit widths, but that's not usually the case). 如果联合中的项目与布局兼容 (如标准中所定义),则可以执行此操作,但intchar情况并非如此(更正确的是,如果这两种类型具有相似的位宽,但通常不是这种情况)。

From the C++03 standard (superceded by C++11 now but still relevant): 从C ++ 03标准(现在已由C ++ 11取代,但仍然相关):

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. 在联合中,最多可以在任何时间激活一个数据成员,即,最多可以在任何时间将一个数据成员的值存储在一个联合中。

I think you may want to look into reinterpret_cast if you want to do this sort of overlaying activity. 我想如果您想进行这种叠加活动,则可能需要研究reinterpret_cast


In terms of what's actually happening under the covers in the first one, the hex value of the number output: 根据第一个幕后的实际情况,数字输出的十六进制值:

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

should provide a clue. 应该提供一个线索。 The yc='B' is only setting the single byte of that structure, leaving the other three bytes (in my case) as indeterminate. yc='B'仅设置该结构的单个字节 ,而其余​​三个字节(在我的情况下)则不确定。

By putting in the yx=65 line before that point, it's setting all four bytes, with those three spare ones being set to zero. 通过在该点之前放置yx=65行,它将设置所有四个字节,并将这三个备用字节设置为零。 Hence they stay at zero when you set the single byte in the following assignment. 因此,当您在以下分配中设置单个字节时,它们保持为零。

Well, you kinda explained the first case when you showed your understanding of the second case. 好吧,当您对第二种情况有所了解时,您就可以解释第一种情况。

Initialising the character part only modifies one byte in a datatype that provides int . 初始化字符部分只会修改提供int的数据类型中的一个字节。 Assuming 32-bit int, that means 3 bytes are still uninitialised... Hence the garbage. 假设int为32位,则意味着3个字节仍未初始化。

Here's the memory usage of your union: 这是您的联合的内存使用情况:

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

When you set x , you set an integer, so all remaining bytes are initialised. 设置x ,设置整数,以便初始化所有剩余字节。 When you set c , you only modify a single byte. 设置c ,仅修改单个字节。

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

This has undefined behaviour. 这具有不确定的行为。 At any given time, union contains only one of its members. 在任何给定时间,工会仅包含其成员之一。 You cannot try to read the int member if it actually contains the char member. 如果int成员实际上包含char成员,则不能尝试读取它。 Because the behaviour of this is not defined the compiler is allowed to do what it wants with the code. 由于未定义此行为,因此允许编译器使用代码执行所需的操作。

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

That is to say, an integer and a character take up different amounts of memory (in the average computer these days, int is 4 bytes, char is 1 byte). 也就是说,一个整数和一个字符占用不同的内存量(在当今的普通计算机中,int是4个字节,char是1个字节)。 The union is only as large as it's largest member. 工会的规模仅与其最大的会员一样大。 Thus, when you set the char, you only set 1 byte of memory - the other 3 bytes are just random garbage. 因此,当您设置字符时,您只设置了1个字节的内存-其他3个字节只是随机垃圾。

Either set the biggest member of the union first, or do something like: 首先设置工会的最大成员,或执行以下操作:

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

to fill the entire union with zero. 用零填充整个联合

In a union, memory allocated is equal to the size of the largest member,which in your case is int ie 2 bytes in case of 16-bit compiler. 在联合中,分配的内存等于最大成员的大小,在您的情况下为int,即对于16位编译器为2个字节。 All members use the same memory space to store their data, hence practically, only one type of member can be stored at a time. 所有成员都使用相同的存储空间来存储其数据,因此,实际上一次只能存储一种类型的成员。

When you assigned the value 'B' to the char member it stored 66 in its memory space of 1 byte. 当您将值'B'分配给char成员时,它将66存储在其1字节的存储空间中。 Then you tried to output the value of the int member which however tried to compute a value by reading values from 2 bytes of the memory, hence you got a garbage value. 然后,您尝试输出int成员的值,但是该成员试图通过从内存的2个字节中读取值来计算值,因此得到了一个垃圾值。

Local variables (more specifically variables on the stack, ie having storage class "automatic") of POD type aren't initialised to anything when they are declared, so the 3 bytes (or 7 bytes on a 64-bit system) not affected by your assignment to yc will contain random garbage. 声明时,POD类型的局部变量(更具体地说是堆栈中的变量,即具有“自动”的存储类)不会初始化为任何东西,因此3个字节(在64位系统上为7个字节)不会受到影响您对yc的分配将包含随机垃圾。

Also note that the particular byte affected by the assignment to yc depends on the endianness of the CPU, so this code will behave differently on different systems even if you initialise yx before assigning to yc . 还要注意,受yc赋值影响的特定字节取决于CPU的字节顺序,因此即使在将yx赋值给yc之前初始化yx ,此代码在不同的系统上也会有不同的行为。

The variable y is of the union type, and the y's length is four bytes. 变量y是联合类型,并且y的长度为四个字节。 For instance, y's memory layout is like this: 例如,y的内存布局是这样的:

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

1) In the first program, the sentence yc='B'; 1)在第一个程序中,句子yc='B'; just set byte1, but byte2, byte3, byte4 are random values in the stack. 只需设置字节1,但字节2,字节3,字节4是堆栈中的随机值。

2) In the second program, the sentence yx=65; 2)在第二个程序中,句子yx = 65; set byte1 as 65 , the byte2, byte3, byte4 is zero. 将byte1设置为65,则byte2,byte3,byte4为零。 Then, the sentence yc='B'; 然后,句子yc='B'; set byte1 as the integer ASCII value of 'B', hence giving an output of 66. 将byte1设置为ASCII整数值“ B”,因此输出为66。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM