当我发现一些奇怪的东西时,我才刚开始接触工会
如果我运行此程序
#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。 任何人都可以解释第一个案例吗?
答案 0 :(得分:2)
从一个不是最后一个写入的工会成员读取实际上是未定义的行为。
如果联合中的项目布局兼容(如标准中所定义),则可以执行此操作,但int
和char
不是这种情况(更准确地说,如果这两种类型具有相似的位宽,可以就是这种情况,但通常情况并非如此)。
从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。