1.为什么要对齐
理论上对任何变量的访问可以从任何地址开始,实际情况是在访问特定类型变量的时候经常在特定的内存地址访问。
2.什么是对齐
需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
3.不对齐的后果
最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。
硬件平台对存储空间的处理上有很大的不同,有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误。
4对齐原则
4.1
原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以该元素自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。
原则二:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
补充:前面所介绍的都是元素为基本数据类型的结构体,那么含有指针、数组或是其它结构体变量或联合体变量时该如何呢?
包含指针类型的情况。只要记住指针本身所占的存储空间是4个字节就行了,而不必看它是指向什么类型的指针。
包含结构体的情况。首先找出子结构体的长度最长元素,然后子结构体内其他元素以该元素整数倍对齐,最后父结构体中的子结构体用n(n为子结构体元素个数)个子结构体中的最长元素代替,其他按规则一二代替。
5
__packed struct can_info
{
uint32_t bus_state; /*总线状态*/
uint8_t rec; /*接收错误计数*/
uint8_t tec; /*发送错误计数*/
uint8_t lec; /*上次错误代码*/
uint8_t boff; /*总线关闭标志*/
uint8_t epvf; /*错误被动标志*/
};
在单片机之类的arm芯片,内存是比较小的,这是就会用按指定的字节对齐以节约内存(虽然会牺牲一些时间)。另外,用于通信的结构体字节对齐后能够产生预期的数据,若让系统自动对齐,会与通信协议格式有偏差!