c中结构体边界对齐
原则1、普通数据成员对齐规则:第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2、结构体成员对齐规则:如果一个结构里有某些结构体成员,则该结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
原则3、结构体大小对齐规则:结构体大小也就是sizeof的结果,必须是其内部成员中最大的对齐参数的整数倍,不足的要补齐。
补 充一点,如果数组作为结构体成员,比如:char a[3]。它的对齐方式和分别写3个char是一样的,也就是说它还是按1个字节对齐。如果写: typedef char Array3[3];Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度3对齐。如果共用体作为结构体成员,则该共用体成员要从其内部 最大元素大小的整数倍地址开始存储。
例1:struct {
short a1;
short a2;
short a3;
}A;
struct{
long a1;
short a2;
}B;
sizeof(A) = 6; 这个很好理解,三个short都为2。
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个字节。