一、啥是字对齐?为啥要字对齐?
字节对齐的原因大致是如下两条:
1、渠道原因(移植原因):不是一切的硬件渠道都能拜访恣意地址上的恣意数据的;某些硬件渠道只能在某些地址处取某些特定类型的数据,不然抛出硬件反常。
2、功能原因:数据结构(尤其是栈)应该尽或许地在天然鸿沟上对齐。原因在于,为了拜访未对齐的内存,处理器需求作两次内存拜访;而对齐的内存拜访仅需求一次拜访。
二、对齐规矩
规矩:
1. 数据成员对齐规矩:结构(struct)(或联合(union))的数据成员,榜首个数据成员放在offset为0的当地,今后每个数据成员的对齐依照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2. 结构(或联合)的全体对齐规矩:在数据成员完结各自对齐之后,结构(或联合)自身也要进行对齐,对齐将依照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3. 结合1、2可推断:榜首、假如n大于等于该变量所占用的字节数,那么偏移量有必要满意默许的对齐方法,第二、假如n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不必满意默许的对齐方法。
三、X86对齐试验
1. 数据类型自身的对齐值:关于char型数据,其自身对齐值为1字节,关于short型为2字节,关于int,float,double类型,其自身对齐值为4字节。
2. 结构体的自身对齐值:其成员中自身对齐值最大的那个值。
3. 指定对齐值:#pragma
4. 数据成员和结构体的有用对齐值:数据成员(数据类型)和数据结构的自身对齐值和指定对齐值中小的那个值,数据成员对齐了数据结构天然也就对齐了。
了解上述四个基本概念,咱们开端评论详细数据结构的成员和其自身的对齐方法。有用对齐值N是终究用来决议数据寄存地址方法的值。有用对齐N,便是表明“对齐在N上”,也便是说该数据的”寄存开端地址%N=0″。而数据结构中的数据变量都是按界说的先后次序来排放的。榜首个数据变量的开端地址便是数据结构的开端地址。结构体的成员变量要对齐排放,结构体自身也要依据自身的有用对齐值圆整(结构体成员变量占用总长度需求是对结构体有用对齐值的整数倍)。下面结合VS2005中编译环境的比如进行深化了解:
比如B剖析:
struct B
{
char b;
int a;
short c;
};
假定B从地址空间0x0000开端排放。该例中没有显式指定对齐值N,VS2005默许值为4。
成员变量b自身对齐值是1,比指定或默许指定对齐值4小,故有用对齐值为1,其寄存地址0x0000契合0x0000%1=0,满意字节对齐准则。
成员变量a自身对齐值为4,和指定或默许指定对齐值4持平,故有用对齐值也为4,为了确保字节对齐,成员变量a只能寄存在开端地址为0x0004到0x0007这四个接连的字节空间中,复核0x0004%4=0。
成员变量c自身对齐值为2,比指定或默许指定对齐值4小,故有用对齐值为2,可次序寄存在0x0008至0x0009两个字节空间中,契合0x0008%2=0。
至此满意了数据成员的字节对齐,接着看数据结构B的对齐。数据结构B的自身对齐值为其变量中最大对齐值(也便是成员变量b)4,故结构体B的有用对齐值也是4。依据结构体圆整的要求, 0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B 共有12个字节,sizeof(struct B)=12。
之所以在变量C弥补2字节,是由于要完成编译器快速有用的存取结构数组,试想假如界说B结构数组,榜首个结构开端地址是0没有问题,可是第二个结构呢?依照数组的界说,数组中一切元素都是紧挨着的,假如不把结构的巨细弥补为对齐值(4)的整数倍,那下一个结构的开端地址将是0x0000A,这明显不能满意结构的地址对齐了。
比如C剖析:
__align(2) struct C
{
char b;
int a;
short c;
};
四、ARM渠道的对齐问题
在ARM中,有ARM和Thumb两种指令。
ARM指令:每履行一条指令,PC的值加4个字节(32bits).一次拜访4字节内容,该字节的开端地址有必要是4字节对齐的方位上,即地址的低两位为bits[0b00],也便是说地址有必要是4的倍数。
Thumb指令:每履行一条指令,PC的值加2个字节(16bits).).一次拜访2字节内容,该字节的开端地址有必要是2字节对齐的方位上,即地址的低两位为bits[0b0],也便是说地址有必要是2的倍数。
五、ARM渠道字节对齐关键字
1. __align(num)
A、在汇编中运用LDRD或许STRD时,就用到此指令__align(8)进行润饰约束。来确保数据目标是相应对齐。
B、该润饰目标的指令最大是8个字节约束,可让2字节的目标进行4字节
C、 __align是存储类修正,他只润饰第一流类型目标不能用于结构或许函数目标。
2. __packed
__packed是进行一字节对齐。
A、不能对packed的目标进行对齐;
B、一切目标的读写拜访都进行非对齐拜访;
C、float及包括float的结构联合及未用__packed的目标将不能字节对齐;
D、__packed对部分整形变量无影响;
D、强制由unpacked目标向packed目标转化是未界说,整形指针能够合法定
义为packed __packed int* p; //__packed int 则没有意义。
3. __unaligned
六、怎么查找与字节对齐方面的问题
假如呈现对齐或许赋值问题首要检查:
1. 编译器的big little端设置;
2. 看这种系统自身是否支撑非对齐拜访;
3. 假如支撑看设置了对齐与否,假如没有则看拜访时需求加某些特别的润饰来标志其特别拜访操作。
七、定论
typedef struct tag_T_MSG{
long ParaA;
long ParaB;
short ParaC;
char ParaD;
char Pad;
} T_MSG;