联合体union赋值被覆盖问题
第一章 引言
最近在学习C++内容,刚好学到了联合体union,在给union内变量赋值时发现了一个很有意思的现象,假如union中有两个int类型的变量,先后进行赋值,从内存中可发现第二个Int型变量的数值将第一个Int型变量数值覆盖了,接下来从内存的情况直观的观察这一现象,并提出思考。
第二章 结构体/联合体变量存储空间分配
想从内存观察联合体变量赋值问题,首先要搞明白其变量在内存中的存储规则。在32位系统中,CPU眼中内存布局如下:
4个字节为一行进行存储,int,char,double,float,short分别有其固有的存储规则,例如Int型变量存储后,需要结构体当前所占用的总存储空间字节数是4的整数倍,下面将列举常见数据类型需要满足的倍数:
数据类型 | 倍数 |
---|---|
int | 4的整数倍 |
char | 任意倍数 |
double | 8的整数倍 |
short | 偶数的整数倍 |
float | 4的整数倍 |
上方表格只是作为参考,下面将举例详细说明倍数在实际存储中的应用,例如下图定义了结构体Score
图中蓝色块代表double类型所占的内存,一个块表示一个字节,绿色块表示char类型所占的内存,红色块儿表示Int类型所占的内存,下面同理,首先存储double类型变量,占8个字节,然后存储1个字节的char,由于存int时需要保证存储后总的字节数是4的整数倍,故char后面3个字节将不存储数据,从第4个字节开始存储Int类型的变量
思考:如果Score中char类型和double类型交换顺序定义,会发生什么事情呢?
由于存放double时,需要保证存放后总的字节数是8的整数倍,故char后面的7个字节将不存放数据,从第8个字节开始存放double类型的变量。
代码验证:
#include<iostream>
using namespace std;
struct S1
{
char level;
double ds;
int a;
};
int main()
{
S1 test;
test.level = 'A';
test.ds = 12.2;
test.a = 4;
return 0;
}
下图为在VS编译器中内存的状态
可从图中右下角看出从0x0031FC2C地址开始现将A的41存入第一个字节中,随后空出7个字节的内存区域去存double类型的12.2,最后去存int类型的4。
第三章 union多个参数赋值被覆盖过程
第二章讲解了结构体中不同数据类型变量在内存中存储规则,联合体union和结构体存储的唯一区别就是:联合体是多个变量共用同一个存储区域,这块儿存储区域的字节数是联合体中占字节数最大的数据类型所对应的字节数。例如union中有int和double两种数据类型,则union的存储空间字节数就是8。又如union中只有char型,则union的存储空间字节数就是4。
下面将演示union中多个变量赋值的过程:
#include<iostream>
using namespace std;
union Score
{
double a;
int b;
};
int main()
{
Score test;
test.a = 62.2;
test.b = 54;
return 0;
}
首先对test中的a赋值62.2之后,内存中的变化(红色):
然后对test中的b赋值后,内存中的变化(红色):
上图可发现,内联体中原本存储a的空间被b改变了,由9a 99 99 99变为99 19 4f 40。若此时将test.a输出,则结果不会是原本的62.6,其数值将会被改变。输出b和a的值留给读者自行观察。
第四章 本文的不足
本文演示了内连体union在赋值的过程中变量值被覆盖问题,文中有很多不足之处,欢迎大家在评论区批评指正。
文本的不足:
文中只是演示了内联体在变量赋值过程中值被覆盖的过程,并没有详细介绍此操作在实际工程中的影响,也没有说明此操作在实际工程中的作用以及为什么要这么做。