首先来看这样一个例子:
struct X {
char a; // 1 bytes
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
char padding3[4]; // 4 bytes
};
要求计算上述结构体的大小,之前接触过的同学,可能有点茫然,是不是按照每个元素的空间相加得到呢?其实不然,虽然上述的代码在计算输出之后和相加得到的值相等,来看这篇文章的一段话:
结构体计算要遵循字节对齐原则。
结构体默认的字节对齐一般满足三个准则:
1、结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2、结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal
adding);
3、结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing
padding)
这里个人认为只需要牢牢记住结构体的总大小为结构体最宽基本类型成员大小的整数倍这句话即可,然后遵循搭积木原则,如何实现呢,就以上述代码为例:
首先找到最宽类型的成员double d,占了8 bytes,然后下一行放入char a,占了1 bytes,如果还没有记住这些基本常量的同学赶紧去背一下,以后所有成员的累加长度不得超过该限制,接下来放入char padding1[3]和float b:
这两个共占了7 bytes,所以说下一位成员要从下一行开始:
最后加入后买那个两位成员:
最后结果是 8bytes * 4(行) = 32bytes
这个例子是很完美的,没有出现行内空缺的情况,但是如果变化一下结果该结构体的成员位置,结果也会随之改变:
struct X {
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
char padding3[4]; // 4 bytes
char a; // 1 bytes
};
cout << sizeof(X)<< endl; //40
模型图如下所示:
可以得出原因:
由于第二行,int c的大小加上第二行已有的数据,则会大于8 bytes,所以只能放到下一行,这样就会比之前的结构体多出一行,使得:
最后结果是 8bytes * 5(行) = 40bytes