结构体的内存分配原则 原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。) 原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员(若结构体内部含结构体成员,则求出该结构体成员的最宽数据类型,和 原结构体中最宽基本类型比较,取两者的最大值作为 整个结构体的内部最大成员)的整数倍,不足的要补齐。 这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。 例1:struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; 这个很好理解,a1 offset为0,short占2字节,此时判断a2,a2 为 short, 占2字节,所以其存储的起始位置必须从2的整数倍开始,而a1刚好2个字节,所以a1之后不需要填充。同样的道理,a3占两个字节。此时总共占6字节,根据原则3,总空间大小必须为其最大元素的整数倍,6满足是2的整数倍,所以A占6字节。 sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。 例2:struct A{ int a; char b; short c; }; struct B{ char b; int a; short c; }; sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。 sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。 深究一下,为什么是这样,我们可以看看内存里的布局情况。 a b c A的内存布局:1111, 1*, 11 b a c B的内存布局:1***, 1111, 11** 其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。 B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。 再看一个结构中含有结构成员的例子: 例3:struct A{ int a; double b; float c; }; struct B{ char e[2]; int f; double g; short h; struct A i; }; sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。
a b c A的内存布局:1111, * * * *, 1111, 1111, 1111, * * * * sizeof(B) = 48; 看看B的内存布局。 e f g h i B的内存布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * * i其实就是A的内存布局。i的起始位置要为8的倍数,所以h后面要补齐。最后总的字节数必须是内部最大成员的整数倍,如果有结构体子成员,求出结构体子成员中最宽类型和原结构体中最宽基本类型中的最大值作为最大成员 。 B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。B 为 48字节,为最大数据成员double 的整数倍。 <pre name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: Arial; zoom: 1; line-height: 22px; background-color: rgb(255, 252, 246);">struct A{
int a;
double c;
};
// A 16字节;
struct B{
char e[2];
int f;
int g;
short h;
struct A i; // i 的起始位置必须是 struct A中最大宽度元素(double型)的整数倍
short t;
};
B: 11** 1111 1111 11** 1111**** 11111111 11****** , 40个字节;注意最后的填充6字节,是为了满足条件3(其中,最宽数据类型为 struct A 中的double类型)