【C语言】结构体大小的计算(内存对齐)
内存对齐原因
①一些平台只能在特定的地址处访问特定类型的数据;
② 提高存取数据的速度,比如有的平台每次都是从偶地址处读取数据,对于一个int类型的变量,若从偶地址单元存放,则只需要一个读取周期即可,但是从奇地址单元存放,则需要2个读取周期读取该变量。
内存对齐原则
①结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
②结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
③ 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)
计算
按照“搭积木”的方式,首先找到成员中所占字节数最大的成员变量,将这一成员变量的大小作为基准,然后按照结构体定义成员的顺序“盖楼”。在一层已满或不能装下下一个变量时,在扩建一层。最后计算层数,乘上所占字节数最大成员变量的大小,得到结构体的大小。
示例1
struct X {
char a; // 1
char padding1[3]; // 3
float b; // 4
int c; // 4
char padding2[4]; // 4
double d; // 8
unsigned int e; // 4
char padding3[4]; // 4
};
若有如上结构体,首先找到所占字节数最大成员变量 double d;
,所以基准就是 8个字节。
下面列出每层楼的成员:
char a;
+char padding1[3];
+float b;
//1+3+4
int c;
+char padding2[4];
//4+4
double d;
//8
unsigned int e;
+char padding3[4];
//4+4
4*8 = 32 字节
示例2
struct X {
char padding1[3]; // 3
float b; // 4
int c; // 4
char padding2[4]; // 4
double d; // 8
unsigned e; // 4
char padding3[4]; // 4
char a; // 1
};
若有如上结构体,首先找到所占字节数最大成员变量 double d;
,所以基准就是 8个字节。
下面列出每层楼的成员:
char padding1[3];
+float b;
//3+4
int c;
+char padding2[4];
//4+4
double d;
//8
unsigned int e;
+char padding3[4];
//4+4
char a;
//1
虽然第一层没有装满,但是加上int c;
大小就会大于8字节,所以只能放到下一层,这样就会比之前的结构体多出一层。
5*8 = 40 字节