前言
在很多C语言的笔试题中都会出现计算一个结构体变量占据的空间大小的题目,当结构体中只包含一些基本元素(char,int等)也许还能轻易看出来,但是当结构体中嵌套了各种各样的数组或者又嵌套了结构体之后就会显得些许复杂,下面将尽量详细并彻底地解决这个问题。
一、三大原则
如上图所示,结构体中包含a,b两个成员变量,结构体变量的起始地址为start,终止地址为end,a与b相对start的偏移量为offset1,offset2。
针对起始地址,终止地址,偏移量的三大原则如下:
- 原则1:结构体首地址(start)是结构体中最大基本数据类型成员所占空间的整数倍
- 原则2:结构体中的成员偏移量(offset)是该成员所占字节的整数倍
- 原则3:结构体的总大小(end-start)是结构体中最大基本数据类型成员所占空间的整数倍
- 结构体中的数组可以看做基本数据类型的集合,比如,char a[3],可以看做3个char型成员的集合
- 结构体中嵌套的结构体也是用上面三大原则分析即可。
按照上面三大原则,就可以判断出各种类型结构体占据的空间大小以及成员分布情况。
二、示例分析(均已验证)
包含基本数据类型
struct {
char var1;
int var2;
char var3;
} a;
- 根据原则1,变量a的首地址是最大基本数据类型(int)所占空间整数倍,因此可以将地址0作为结构体首地址
- 根据原则2,var1的偏移量offset1=0,var2的偏移量offset2=4,var3的偏移量offset3=8
- 根据原则3,结构体的总大小是最大基本数据类型(int)所占空间的整数倍,因此结构体占据空间为12,需要末尾补齐3个字节
综上,结构体a所占的空间sizeof(a)等于12字节。
内存分布如下:
包含数组
struct {
char var1;
int var2[2];
double var3;
} a;
上文已提到,在结构体中出现的数组可以当成基本数据类型的集合,因此分析如下:
- 根据原则1,变量a的首地址是最大基本数据类型(double=8字节)所占空间整数倍,因此可以将地址0作为结构体首地址
- 根据原则2,var1的偏移量offset1=0,var2的偏移量offset2=4,var3的偏移量offset3=16
- 根据原则3,结构体的总大小是最大基本数据类型(double)所占空间的整数倍,因此结构体占据空间为24
综上,结构体a所占的空间sizeof(a)等于24字节。
内存分布如下:
包含结构体
struct {
char var1;
int var2[2];
struct {
char var3;
double var4;
} b;
} a;
在上文中,我们都是直接将结构体的首地址设置为0,因为0是所有数的整数倍。那原则1岂不是提出来就没用了?其实不然,原则1的作用是为了确定结构体中的结构体成员偏移量,即上方的结构体成员b。
分析如下:
- 根据原则1,变量a的首地址是最大基本数据类型(double=8字节)所占空间整数倍,注意不是将结构体成员b的类型作为基本数据类型,因此可以将地址0作为结构体首地址
- 根据原则2,,var1的偏移量offset1=0,var2的偏移量offset2=4,接下来分析结构体成员b的首地址,此时根据原则1,b的首地址应该是double所占空间整数倍,因此b的地址偏移量offset_b=16,在此基础上,相对于b的首地址,var3的偏移量offset3=0,var4的偏移量offset4=8。
- 结构体的总大小是最大基本数据类型(double)所占空间的整数倍,因此结构体占据空间为32字节。
内存分配情况如下: