首先,在没有#pragma pack的情况下,要遵循如下几个原则:
原则1、普通数据成员对齐规则:第一个数据成员放在offset为0的地方(可假设起始位置为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对齐。如果共用体作为结构体成员,则该共用体成员要从其内部最大元素大小的整数倍地址开始存储,如果是枚举类型作为结构体成员,则该枚举类型默认从int大小的整数倍地址开始存储
还有一种对齐原则,和上面三条一致,可以参考着理解。
成员对齐有一个重要的条件,即每个成员按自己的方式对齐。其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。
这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。
例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个字节。
再看一个结构中含有结构成员的例子:
例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。
sizeof(B) = 48; 看看B的内存布局。
e f g h i B 的内存布局:11* *,1111,11111111, 11 * * * * * *,1111* * * *, 11111111,
1111 * * *
* 。 i其实就是A的内存布局。i的起始位置要为8(此处我个人觉得应该为8的倍数,
http://blog.csdn.net/b_h_l/article/details/7738217原引用处为24,)的倍数,所以h后面要补齐。把B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。
以上讲的都是没有#pragma pack宏的情况,如果有#pragma
pack宏,对齐方式按照宏的定义来。比如上面的结构体前加#pragma pack(1),内存的布局就会完全改变。sizeof(A) =
16; sizeof(B) = 32;有了#pragma pack(1),内存不会再遵循原则1和原则3了,(是否还遵循原则2?目前还没搞清楚)按1字节对齐。没错,这不是理想中的没有内存对齐的世界吗。
a b c
A的内存布局:1111,11111111,1111
e f g h i B的内存布局:11,1111,11111111,11,1111, 11111111,
1111