最近一口君在做项目,遇到了一个问题。运行在ARM上的threadx是使用消息队列与DSP通信传递消息(最终实现原理是中断+共享)在实际运行过程中,发现threadx总是死机,所以查了一下,是因为消息传递的结构不考虑字节对齐问题,整理出C语言中的字节对齐问题,分享给大家1.概念对齐与数据在内存中的位置有关,如果一个变量的内存地址恰好是其的整数倍它的长度,就说它是自然对齐的。比如在32位CPU下,如果一个整型变量的地址是0x00000004,那么它就是自然对齐的。首先要明白什么是位、字节、字long。现代计算机的字长通常为16、32或64位。(一般N位系统的字长为N/8字节。)不同的CPU一次可以处理不同的数据位。32位CPU可以处理3一次2位数据,64位CPU一次可以处理64位数据。这里的位是指字长。所谓字长,我们有时称之为字(word)。在16位CPU中,一个字恰好是两个字节,而在32位CPU中,一个字是四个字节。如果以字为单位,向上还有双字(twowords)、四字(quadrupleword)。2.对齐规则对于标准数据类型,其地址只需为其长度的整数倍,非标准数据类型按照以下原则进行对齐: 数组:按照基本数据类型对齐,第一个是对齐的,后面自然是对齐的。Union:按其包含的最大长度数据类型对齐。结构:结构中的每个数据类型都必须对齐。3.如何限制固定字节对齐的个数?1.默认默认情况下,C编译器根据其自然边界条件为每个变量或数据单元分配空间。通常,可以通过以下方法改变默认的对齐条件:2.#pragmapack(n)·使用伪指令#pragmapack(n),C编译器将按照n字节对齐。·使用指令#pragmapack()取消自定义字节对齐。#pragmapack(n)用于设置变量对齐n字节。N字节对齐是指变量存储起始地址的偏移量有两种情况:如果n大于等于变量占用的字节数,那么偏移量必须满足默认对齐方式;如果n小于变量的类型占用的字节数,那么偏移量是n的倍数,不需要默认对齐。结构的总大小也有约束。如果n大于等于所有成员变量类型占用的字节数,那么结构体的总大小必须是空间占用最大的变量占用空间的倍数;否则它必须是n的倍数。3.__attribute此外,还有一种方式如下:·__attribute((aligned(n))),让作用结构体成员在n字节的自然边界上对齐。如果结构中任意成员的长度大于n,则按照最大成员的长度对齐。·attribute((packed)),取消编译时结构体的优化对齐,按照实际占用字节数对齐。4.汇编.align汇编代码通常使用.align来指定对齐的字节数。.align:用于指定数据的对齐方式,格式如下:.align[absexpr1,absexpr2]以一定的对齐方式填充未使用的存储区。第一个值表示对齐方式,4、8、16或32。第二个表达式值表示填充值。4、为什么需要对齐?操作系统不是逐字节访问内存,而是按2、4、8等字长访问内存。因此,CPU从内存读取数据到寄存器时,IO的数据长度通常为字长。例如,32位系统的访问粒度为4字节,64位系统为8字节。当要访问的数据长度为n字节,数据地址对齐n字节时,操作系统可以一次性高效定位数据,不需要多次读取、处理对齐操作等额外操作。数据结构应尽可能在自然边界上对齐。如果访问未对齐的内存,CPU需要进行两次内存访问。字节对齐可能带来的隐患:代码中很多关于对齐的隐患都是隐含的。例如,在强制类型转换的情况下。例如:unsignedinti=0x12345678;unsignedchar*p=NULL;unsignedshort*p1=NULL;p=&i;*p=0x00;p1=(unsignedshort*)(p+1);*p1=0x0000;的最后两行代码,从Odd边界访问unsignedshort类型的变量,显然不符合对齐要求。在x86上,类似的操作只会影响效率,但在MIPS或sparc上,可能会报错,因为它们需要字节对齐。5、例1:os基本数据类型占用的字节数首先查看运行系统的位数查看64位操作系统下基本数据类型占用的字节数:#include
