原因
??32 位处理器每次最多可以处理 32 位数据(也就是 CPU 的数据线是 32 位的,这里可以了解地址线和数据线),但是许多数据只需要 8位,16 位。比如文本处理常用的 ASCII 码,只需要 8 位,即使用 Unicode,也只要16位,所以 32 位处理器基本都具备处理更短位数数据的能力,也就是并非每次都一定要取 4 个字节的数据。实际上,计算机并非总是逐字节大小读写内存,而是以 2、4 或 8 的倍数的字节块来读写内存,有时也会只取一个字节。需要注意的是,只有位于 0x00、0x02、0x04、··· 的可以被 2 整除的位置上才会采取以 2 的倍数的字节块读写内存,只有位于 0x00、0x04、0x08、··· 位置上才会采取 4 的倍数的字节快读写内存,同理有 8 的倍数的字节块。 ??计算机在取数据的时候,偏向于取数据次数较少的取数方案,如一个 int 数据位于 0x02 上,那么计算机会先从 0x02-0x03 上取一个 short,然后从 0x04-0x05 上一个 short,两个拼接一起就是一个 int,需要取数 2 次。如果在 0x03 处,那么会先从 0x03 上取一个 char,然后从 0x04-0x05 上取一个 short,再从 0x06 上取一个 char,拼接成一个 int,需要取数 3 次。 ??如果 int 正好位于 0x00 或 0x04 等位置,那么它只需要取数一次即可。因此,常常希望这些基本类型能够位于对齐的位置上,方便一次取出。
一些概念
自身对齐值
基本类型的自身对齐值
为指定平台上基本类型的长度。对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
结构体或类的自身对齐值
其成员中自身对齐值最大的那个值。
指定对齐值
#pragma pack (value) 时的指定对齐值 value。
有效对齐值
自身对齐值和指定对齐值的较小值。
对齐原则
基本数据类型对齐原则
地址是长度的整数倍。
数组的对齐原则
按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。
联合的对齐原则
按其包含的长度最大的数据类型对齐。
结构体的对齐原则
每个成员都要对齐,编译器可能需要在结构体字段的分配中插入间隙,以保证每个结构元素都满足它的对齐要求。第一个数据变量的起始地址就是数据结构的起始地址。结构体本身也要根据自身的有效对齐值圆整(就是结构体总长度需要是结构体有效对齐值的整数倍),此时可能需要在结构末尾填充一些空间,以满足结构体整体的对齐—-向结构体元素中最大的元素对齐。简而言之就是 (1)每个成员必须对齐,其地址可以被自身长度整除;(2)对于第一个元素,其地址应该可以被整个结构体的对齐字节数整除;(3)整个结构体是圆整的,总长度为最大长度数据成员的整数倍。
实例
下面的结构体的 sizeof 是多少?
struct test
{
char a;
int b;
short c;
char d;
};
正确答案:12 如果首地址是 0x00,在内存中的图示可能是这样的:
|