结构体的大小计算
结构体中可以定义的数据类型:
1.基本类型
2.上面已经出现过的数据类型,比如说上面已经定义过的结构体
3.指向自己的指针
因为内存对齐的问题,各个数据类型放的位置不同就会导致结构体的大小不一样,那么到底怎样计算一个结构体的大小呢?
先介绍一个概念——偏移量,结构体中的偏移量就是结构体成员和结构体变量的地址之差,比如说第一个结构体成员的偏移量就是0,第二个结构成员的偏移量就是第一个结构体成员的大小,假如第一个成员的是int b
;那么第二个结构体成员变量的偏移量就是4。
计算结构体大小的规则:
- 每一个成员的偏移量都必须是该成员的倍数。
- 结构体的大小必须是该结构体字节数最大成员类型的倍数。(注意是类型而不是变量)
例如下面的结构体:
例一:
struct A
{
char a;
short b;
int c;
};
第一个成员的偏移量都是0;一般可以不看,a的大小为1,所以成员b的偏移量为1,b的大小为2,1不是2的倍数,所以应该将1+1,成为2的倍数,成员c的偏移量就为1+1+2,是成员c的倍数,现在就符合计算结构体大小的第一条:该成员的偏移量是该成员大小的倍数,还有第二条规则:结构体大小是结构体最大成员的倍数,结构体的大小就是各个成员之和,a;2,b:2,c:4加起来就是8,该结构最大成员为c大小为4,满足第二个条件,所以该结构体的大小就是8。
代码:
#include <stdio.h>
int main ()
{
struct A
{
char a;
short b;
int c;
};
printf ("%d",sizeof(A));
return 0;
}
例二:
struct Data
{
char a;
int b;
int64_t c; 该数据类型是有符号的占64位的整形数据类型
char d;
}
成员a的偏移量就不用看了,上面有说每一个结构体第一个成员的偏移量都为0;但他的大小是1,也就是成员b的偏移量,成员b的大小是4,1不是4的倍数,所以a的大小1应该加上3,就是4,成员3的偏移量是8,成员c的大小是8,成员c的偏移量是成员c大小的倍数,就不用增加大小,成员d的偏移量是16,成员d的大小是1,偏移量是成员大小的倍数,现在就符合计算结构体大小的第一条:改成员的偏移量是该成员大小的倍数,还有第二条规则:结构体大小是结构体最大成员的倍数,最大成员为c,大小是8,结构体的大小就是各个成员之和,a:4,b:4,c:8,d:1所有的加起来就是17,但是17不是8的倍数,所以应该将17+7就是24,所以该结构体的大小就是24。
代码:
#include <stdio.h>
int main ()
{
struct Data
{
char a;
int b;
long long c;
char d;
};
printf ("%d
",sizeof(Data));
return 0;
}
联合体(Union)大小的计算
1.联合体特性
- 联合体所有成员变量共享内存,相对于联合体首地址偏移量都为0
- 同一时间只能存储1个被选择的变量,对其他成员变量赋值会覆盖原变量
2.联合体大小计算规则
- 联合体大小要至少能容纳最大的成员变量
- 联合体大小要是所有成员变量类型最大值的整数倍(注意是类型而不是变量)
例:
typedef union u
{
char a;
int b[5];
double c;
int d[3];
}U;
U大小至少要容纳最大的b[5]=4*5=20字节,同时要是变量类型最大值得整数倍,即sizeof(double)=8的整数倍,所有sizeof(U)=24
结构体嵌入联合体的大小计算
计算规则
联合体按照最大成员所占字节且为最大数据类型所对应的字节的最小整数倍的原则进行计算,它所占的字节数与结构体中其他成员所占字节的总和应为结构体中最大数据类型所对应的字节的最小倍数。
例
typedef struct
{
union
{
char a[10];
int b[2];
double c;
}test;
char d[5];
int e;
double f;
}Test;
根据上述规则,则联合体中,最大占10字节,但又要为8的最小倍数,因此联合体占16字节,然后 16+5+4+8=33 字节,不是结构体中最大数据类型 double 所对应的字节数 8的最小倍数,根据规则故结构体的大小为:16(联合体所占字节)+5+3(空字节)+4+4(空字节)+8=40 字节。
结构体/联合体嵌套结构大小的计算
当结构体里面嵌套有结构体时,其规则为:
1、嵌套的结构体前一个成员的偏移量应当是嵌套结构体中最大成员类型大小的整数倍;
2、结构体成员的大小必须是所有成员大小的整数倍,这里所有成员计算的是包括嵌套结构体内所有成员在内,而不是将嵌套的结构体当做一个整体。
如下例:
#include <iostream>
using namespace std;
struct A
{
char a1;
short int a2;
double a3;
char d;
};
struct B
{
int b2;
A a;
short int b1;
};
int main()
{
cout << sizeof(B)<<endl;
//system("pause");
}
对于A来说,A的大小可以使用之前的方法计算为24。而对于B,由于A结构体中最大成员类型为double,其占字节为8,因而B中的第一个成员b2的偏移量应该是8的倍数,即为8,然后再加上结构体A的大小,为 8 + 24 = 32,再然后加上b1的大小为2,结果为8 + 24 + 2 = 34。根据上面的规则2,其总大小要是所有成员大小的整数倍,因而必须是8的倍数,因而最终结果为40。
当结构体里面嵌套有联合体时
1、嵌套联合体前一个成员的偏移量应当是嵌套联合体中最大成员类型大小的整数倍;
2、结构体成员的大小必须是所有成员类型大小的整数倍,这里所有成员计算的是包括嵌联合体内所有成员在内,而不是将嵌套的联合体当做一个整体。
#include <iostream>
using namespace std;
union A
{
char a1;
short int a2;
double a3[2];
char d;
};
struct B
{
int b2;
A a;
short int b1;
};
int main()
{
cout << sizeof(B)<<endl;
//system("pause");
}
输出为32。
参考资料:
[1] 关于结构体、联合体大小的计算 https://blog.csdn.net/qq_29775205/article/details/86538154
[2] 结构体大小问题:sizeof 嵌套结构体求大小(结构体里有结构体) https://blog.csdn.net/qq_19323819/article/details/82965040?tdsourcetag=s_pctim_aiomsg
C++在线编译器地址:https://c.runoob.com/compile/12