数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽。X86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据时,会在内部进行一系列的调整。这些调整对于程序员来讲是透明的,可是会下降运行速度,因此编译器在编译程序时会尽可能保证数据对齐。ios
不一样的编译器内存对齐的方式不一样。程序员
一个小例子:在32位的机器上,数据是以4字节为对齐单位,这两个类的输出结果为何不一样?(VS2008)数组
答案是:3*4=12,2*4=8布局
分析:在访问内存时,若是地址按4字节对齐,则访问的效率会高不少。性能
考虑到性能方面,编译器会对结构进行对齐处理,考虑下面的结构:spa
struct aStruct.net
{blog
char cValue;内存
int iValue;get
};
直观地讲,这个结构的尺寸是sizeof(char)+sizeof(int)=6,可是在实际编译下, 这个结构尺寸默认是8,由于第二个域iValue会被对齐到第4个字节。
注意:字节对齐是编译时决定的,一旦决定则不会再改变,所以即便有对齐的因素存在,也不会出现一个结构在运行时尺寸发生变化的状况。
在本题中:第一种类的数据对齐是下面的状况:
bool ---- ---- ----
------- int ---------
bool ----- ---- ----
第二种类的数据对齐是下面的状况:
------- int ----------
bool bool ---------
因此类的大小分别3*4和2*4
通常在VC++中加上#pragma pack(n)设置内存对齐。
咱们能够利用#pragma pack()来改变编译器的默认对齐方式。
#pragma pack(n) //编译器将按照n字节对齐
#pragma pack() //编译器将取消自定义字节对齐方式
在#pragma pack(n)和#pragma pack()之间的代码按n字节对齐。
可是成员对齐有一个重要的条件,即每一个成员按照本身的对齐方式对齐;也就是说虽然指定了按n字节对齐,但并非全部的成员都以n字节对齐。
对齐的规则是:每一个成员按其类型的对齐参数(一般是这个类型的大小)和指定对齐参数(这里是n字节)中较小的一个对齐,即min(n,sizeof(item)),而且结构的长度必须为所用过的全部对齐参数的整数倍,不够就补空字节。
运行结果为:8,24
分析:
TestStruct4 中,成员a是1字节,默认按照1字节对齐,指定对齐参数是8,这两个值中取1,a按1字节对齐;
成员b是4字节,默认是按4字节对齐,这时就按4字节对齐,因此sizeof(TestStruct4)应该是8.
TestStruct5 中,c和TestStruct4中的a同样,按1字节对齐;而d是个结构,它是8字节,对于结构来讲,它的默认对齐方式就是其全部成员使用的对齐参数中最大的一个,TestStruct4就是4,因此成员d就按照4字节对齐。成员e是8字节,它是默认的8字节对齐,和指定的同样,因此它对齐到8本身的边界上,这时,已经使用了12字节了,因此又添加了4字节的空间,从第16字节开始放置成员e。这时长度为24,已经能够被8整除(成员e按8字节对齐)。这样一共使用了24字节。
内存布局图以下:
TestStruct4 的内存布局:
a b
1*** 1111
TestStruct5 的内存布局:
c d.a d.b e
1*** 1*** 1111 **** 11111111
注意3点:
(1)每一个成员按照本身的方式对齐,并能最小化长度
(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,能够最小化长度。
(3)对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时能够保证每一项都边界对齐。
补充:对于数组,好比说char a[3],它的对齐方式和分别写3个char是同样的,也就是说它仍是按1字节对齐;若是写成typedef char Arrary3[3],Arrary3这种类型的对齐方式仍是按1字节对齐,而不是按它的长度。
可是不论类型是什么,对齐的边界必定是一、二、四、八、1六、3二、64......中的一个。
下面来讲下大端模式和小端模式
大端模式:认为第一个字节是最高位字节,也就说按照从低地址到高地址的顺序存放数据的高位字节到低位字节。
小端模式:认为第一个字节是最低位字节,也就是说按照从低地址到高地址的顺序存放数据的低位字节到高位字节。
假设从内存地址0x0000开始有如下数据:
内存地址:0x0000 0x0001 0x0002 0x0003
对应数据:0x12 0x34 0x56 0x78
若是咱们去读取一个地址为0x0000的4字节变量
若字节序位为小端模式,读出为:0x78563412
若字节序位为大端模式,读出为:0x12345678
通常来讲:X86系列的CPU都是小端字节序,powerPC一般是大端字节序。
运行结果为:37363534
分析:这里是小端字节序
地址从0x0000开始,那么sz在内存中的存储为:
内存地址: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
对应的值: 0 1 2 3 4 5 6 7 8 9
对应的值: 48 49 50 51 52 53 54 55 56 57
对应的16进制:0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39
sz ++p
因此读取为:0x37363534