sizeof(struct)与sizeof(union)的区别
1、关于struct与union的内存分配方式
(1)、结构体(struct)按照定义时的顺序,为每个成员在内存中依次分配独立空间;
(2)、联合(union)只按成员中最大的类型分配空间,所有成员共享这个内存空间。
如下:
struct St_InfoA
{
int Num1;
int Num2;
int Num3;
};
union U_InfoB
{
int Num1;
int Num2;
int Num3;
};
int main(void)
{
printf("The Size Of St_InfoA:%d\n", sizeof(struct St_InfoA)); /*结果为12*/
printf("The Size Of U_InfoB:%d\n", sizeof(union U_InfoB)); /*结果为4*/
return 0;
}
如上例,一样的成员,为结构体分配的内存空间是12个字节(3*sizeof(int));而在联合中,分配的内存空间是4个字节(按最大类型int进行分配)。
2、关于struct与union的大小计算方式
前面通过简单的示例(成员都是同样的数据类型),展示了关于结构体和联合变量在内存分配时的差别。但对于其大小的计算,并不是简单地将所有成员大小相加(strut类型时)/直接取最大的成员大小(union类型时);而需考虑具体变量在存储时的地址对齐、成员偏移量的问题。在实际的变量存储时,会按照如下的规则进行处理:
-
规则1:结构体/联合 变量中当前成员的偏移量必须是该成员大小的整数倍;
-
规则2:结构体/联合 大小必须是所有成员类型大小的整数倍,也即所有成员类型大小的公倍数。
Ps:偏移量:指的是结构体/联合 变量中成员的地址和该变量地址(变量的起始地址)的差值。
接下来,我们根据以上提到的规则来看看示例中关于结构体和联合大小的计算。
(1)、关于结构体的大小
结构体的大小等于最后一个成员的偏移量加上最后一个成员的大小。如下:
struct St_InfoA
{
char Num1; /*成员偏移量为0*/
int Num2; /*根据第1点规则实际偏移量为4*/
char Num3; /*成员偏移量为8(4+4)*/
};
struct St_InfoB
{
char Num1; /*成员偏移量为0*/
char Num2; /*成员偏移量为1(0+1)*/
int Num3; /*根据第1点规则实际偏移量为4*/
};
int main(void)
{
printf("The Size Of St_InfoA:%d\n", sizeof(struct St_InfoA)); /*结果为12(8(最后一个成员的偏移量)+1(最后一个成员的大小),根据第2点规则实际为12)*/
printf("The Size Of St_InfoB:%d\n", sizeof(struct St_InfoB)); /*结果为8(4(最后一个成员的偏移量)+4(最后一个成员的大小))*/
return 0;
}
上例中,我们定义了两个结构体类型;其成员是一样的(两个char类型,1个int型成员),但由于成员顺序不同,分配内存时数据对齐的操作,输出的类型大小也是不同的。前者占据了12个字节的长度;后者占据了8个字节的长度。
(2)、联合的大小
联合的大小等于考虑字节对齐后最大成员的大小。如下:
union U_InfoA
{
char Buff[6];/*成员大小为6字节*/
int Num; /*成员大小为4字节*/
};
union U_InfoB
{
char Num1; /*成员大小为1字节*/
char Num2; /*成员大小为1字节*/
char Num3; /*成员大小为1字节*/
};
int main(void)
{
printf("The Size Of U_InfoA:%d\n", sizeof(union U_InfoA)); /*结果为8,取最大成员大小6字节,但根据第2点实际大小为8字节*/
printf("The Size Of U_InfoB:%d\n", sizeof(union U_InfoB)); /*结果为1字节*/
return 0;
}
如上例,U_InfoA中最大的成员是Buff[6],占据6个字节;但根据前面描述的第2点,联合大小必须是所有成员类型大小的整数倍(6不是int类型的整数倍);所以实际是按8个字节进行分配处理的。
总结
1、在结构体和联合的内存分配上,有如下差异:
- struct中为每个成员都独立分配空间;
- union只按最大成员的大小进行内存分配,所有成员共享这个内存空间。
2、在对结构体/联合大小进行计算时,需遵循以下两点原则进行数据对齐:
-
结构体/联合 变量中当前成员的偏移量必须是该成员大小的整数倍;
-
结构体/联合 大小必须是所有成员类型大小的整数倍,也即所有成员类型大小的公倍数。
Ps:在需要对结构体/联合的大小进行使用时,不要直观的拿自己认为的数字去代表;在代码中应该以sizeof(结构体/联合类型)去代表其大小。