内存对齐
#pragma pack (n)这个语句用于设置结构体的内存对齐方式,具体作用下面再说。在linux gcc下n可取的值为:1,2,4,当n大于4时按4处理。如果程序中没用显试写出这个语句,那么在linux gcc下,它会对所有结构体都采用#pragma pack (4)的内存对齐方式。需要注意的是,在不同的编译平台上默认的内存对齐方式是不同的。如在VC中,默认是以#pragma pack (8)的方式进行对齐。
内存对齐总规则:
结构体成员的地址必须安排在成员大小的整数倍上或者是#pragma pack(n)所指定的n的倍数上;取两者的最小值,即MIN(sizeof(mem), n),称MIN(sizeof(mem), n)为该结构体的成员对齐模数。同时该结构体的总大小必须为MIN(n, MAX(sizeof(mem1), siezof(mem2)…))的整数倍;而称MIN(n, MAX(sizeof(mem1), siezof(mem2)…))为该结构体的对齐模数。
内存对齐细则:
下面的3条细则符合上面所说的总规则;这里的偏移指某一个数据成员的首地址到该结构体头的地址偏移。
(1)对结构体的成员,第一个数据位于偏移为0的位置,以后每个数据成员的偏移量必须是成员对齐模数的倍数。
(2)为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的偏移是否为成员对齐模数的整数倍,若是,则存放本成员,反之,则在本成员与上一成员之前填充一定的字节,从而达到整数倍的要求。
(3)在数据成员完成自身的对齐后,结构体本身也要进行对齐。意思是该结构体的大小必须是结构体的对齐模数的整数倍。如果其大小不是,那么则在最后一个成员的后面填充字节。
内存对齐完整版规则
1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
如果 n < sizeof(mem), 是从n的整数倍开始。
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
注char【8】看做 8个元素,而不是一个元素
(3)在数据成员完成自身的对齐后,结构体本身也要进行对齐。意思是该结构体的大小必须是结构体的对齐模数的整数倍。如果其大小不是,那么则在最后一个成员的后面填充字节。
Type | 存储所占字节 | 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量) | Alignment 和左边一列一个意思 |
---|---|---|---|
char | 1 | 偏移量必须为sizeof(char)即1的倍数 | 在字节边界上对齐 |
short (16-bit) | 2 | 偏移量必须为sizeof(short)即2的倍数 | 在双字节边界上对齐 |
int and long (32-bit) 指针(unsigned long int) | 4 在32位系统下int 和long是一样的? | 偏移量必须为sizeof(int)即4的倍数 | 在4字节边界上对齐 |
枚举类型的默认类型是int型 | 4 | ||
float | 4 | 偏移量必须为sizeof(float)即4的倍数 | 在4字节边界上对齐 |
double long long | 8 | 偏移量必须为sizeof(double)即8的倍数 | 在8字节边界上对齐 |
structure | 单独考虑结构体的个成员,它们在不同的字节边界上对齐。 其中最大的字节边界数就是该结构的字节边界数。 | ||
静态变量 | 0 | MSDN原话:Largest alignment requirement of any member | |
空结构体 | 1 必须保证结构体的每一个实例在内存中都有独一无二的地址 |
***************************************>【例题】<*****************************************
例题1:
typedef struct{
int i;
char c;
short s;
char buf[21];
}s; //32
例题2:
typedef struct {
int id; //[0]..[3]
char name[50]; // [4]..[53]
int age; //[56..59]
char gender[10]; //[60..71]
} s; // 72
例题3:
struct stu{
char sex; //[0]
int length; // [4]…[7]
char name[10]; //[8]..[17] //按照模 sizeof(int) = 4补齐
};
sizeof (struct stu) = 20
例题5:
enum DataType {
IntData, CharData, VcharData
}; //4
struct s {
char ItemNAme[30]; //[0..29]
enum DataType ItemType; //[32..35]
char ItemDecr[50]; //[36..85]
int ItemLength; //[88..91]
}; //92
printf("%d\n", sizeof(struct s));
例题7:
typedef struct
{
char str;
short x;
int num;
double xx;
}s1;
typedef struct
{
char str;
int num;
short x;
double xx;
}s2;
例题8:
微软&Intel笔试题:
#pragma pack(8)
struct s1
{
short a;
long b; //4
}; //8
struct s2
{
char c; //[0]
s1 d; //[4..11]
long long e; // [16..23]
}; //24
#pragma pack()
问:
1.sizeof(s2) = ?
2.s2的c后面空了几个字节接着是d?
答:
例题9:
华为笔试题:
typedef struct {
unsigned char ucld :1;
unsigned char ucpara0 :2;
unsigned char ucstate :6;
unsigned char uctail :4;
unsigned char ucavail;
unsigned char uctail2 :4;
unsigned long uldate;
} s;
//s在字节对齐分别为1,4的情况下占用空间大小是多少?还有那个冒号是什么意思