内存对齐作用:
1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某 些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存, 处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
结构体struct内存对齐的3大规则:
1.对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类 型的整数倍;
2.结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用,内存大小是结构体内最大数据成员的最小整数倍;
3.如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再 考虑当前类型以及最大结构体内类型。
#pragma pack(1) //32位默认4个字节一个空间。 这里可以是最少空间可以是1的倍数因为用了
struct fun
{
int i; |x|x|x|x|
double d; |x|x|x|x|x|x|x|x|
char c; |x|
};
sizeof(fun) = 13
struct CAT_s //这里空间可以是4的倍数
{
int ld; // 4 |x|x|x|x|
char Color; // 1
unsigned short Age; // 2 |x|0|x|x| //这是char和short共用四个空间
char *Name; // 4 |x|x|x|x|
void(*Jump)(void); // 4 |x|x|x|x|
}Garfield;
- 1.使用32位编译,int占4, char 占1, unsigned short 占2,char* 占4,函数指针占4个,由于是32位 编译是4字节对齐,所以该结构体占16个字节。(说明:按几字节对齐,是根据结构体的最长类型决定 的,这里是int是最长的字节,所以按4字节对齐);
- 2.使用64位编译 ,int占4, char 占1, unsigned short 占2,char* 占8,函数指针占8个,由于是64位 编译是8字节对齐(说明:按几字节对齐,是根据结构体的最长类型决定的,这里是函数指针是最长的字 节,所以按8字节对齐)所以该结构体占24个字节。
struct C //空间要是8的倍数
{
double t; //8 |x|x|x|x|x|x|x|x|
char b; //1
int a; //4 |x|0|0|0|x|x|x|x|
short c; //2 |x|x|0|0|x|x|x|x|
};
sizeof(C) = 24; //
- char是1,然后在int之前,地址偏移量得是4的倍数,所以char后面补三个字节,也就是char占了4个字 节,然后int四个字节,最后是short,只占两个字节,但是总的偏移量得是double的倍数,也就是8的倍 数,所以short后面补六个字节
联合体union内存对齐的2大规则:
1.找到占用字节最多的成员;
2.union的字节数必须是占用字节最多的成员的字节的倍数,而且需要能够容纳其他的成员
//x64
typedef union {
long i;
int k[5];
char c;
}D
- 要计算union的大小,首先要找到占用字节最多的成员,本例中是long,占用8个字节,int k[5]中都是int类型, 仍然是占用4个字节的,然后union的字节数必须是占用字节最多的成员的字节的倍数,而且需要能够容纳 其他的成员,为了要容纳k(20个字节),就必须要保证是8的倍数的同时还要大于20个字节,所以是24个字 节。