今天遇到一次字节对齐问题,找了半天,突发奇想,怀疑起是不是字节顺讯的问题,终于弄好了。
现象
使用串口接收一串数据,然后将数据整体赋值给结构体,中间使用强制转换,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32typedef struct
{
// 焊接工作标志
uint16_t WorkFlag;
// 应用参数
uint16_t Num; // 焊钳编号
uint16_t Thick; // 材料总厚度
// 电源参数
uint16_t CurrentMax; // 电源最大电流
uint16_t VoltageMax; // 电源最大电压
uint16_t WorkTime[8]; // 电源分段时间参数
uint16_t WorkCurrent[7]; // 电源分段时间参数
uint16_t PowerReserveData[4]; // 电源保留参数
// 焊钳参数
uint16_t Speed; // 打压速度
uint16_t Acc; // 打压加速度
uint16_t S_Calib; // 位移标定参数
uint16_t F_Calib; // 压力标定参数
uint16_t Worn; // 磨损参数
// uint16_t test;
float GunReserveData[12]; // 焊钳保留参数
//焊钳分段压力参数
float Force[4]; // 压力分段参数
//预留参数
uint16_t OtherReserveData[12];// 其他预留参数
// 焊钳开口率
uint16_t OpenRatio;
}QT_RX_PARAM;
*m_rx_param = *(QT_RX_PARAM *)(rx_buf + 4 );
但是浮点数据或者32位数据都向后移动了2个字节
解决办法
中间想了许多办法,但是都没有用处,想到有可能是字节问题,在结构体上使用2字节对齐1
2
3#pragma pack(2)
、、、
#pragma pack()
能力不够,使用__attribute时没能操作成功1
2__attribute((aligned (n))): 让所作用的结构成员对齐在n字节自然边界上。如果结构体中有成员的长度大于n,则按照最大成员的长度来对齐。
__attribute__ ((packed)): 取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
拓展
转载于https://www.cnblogs.com/clover-toeic/p/3853132.html
什么是字节对齐
现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。
对齐的原因和作用
不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种架构下编程必须保证字节对齐。
但最常见的情况是,如果不按照平台要求对数据存放进行对齐,会带来存取效率上的损失。比如32位的Intel处理器通过总线访问(包括读和写)内存数据。每个总线周期从偶地址开始访问32位内存数据,内存数据以字节为单位存放。如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。
因此,通过合理的内存对齐可以提高访问效率。为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址能够被4整除。
此外,合理利用字节对齐还可以有效地节省存储空间。但要注意,在32位机中使用1字节或2字节对齐,反而会降低变量访问速度。因此需要考虑处理器类型。还应考虑编译器的类型。在VC/C++和GNU GCC中都是默认是4字节对齐
对齐的分类和准则
主要基于Intel X86架构介绍结构体对齐和栈内存对齐,位域本质上为结构体类型。对于Intel X86平台,每次分配内存应该是从4的整数倍地址开始分配,无论是对结构体变量还是简单类型的变量。
3.1. 结构体对齐
在C语言中,结构体是种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构体、联合等)的数据单元。编译器为结构体的每个成员按照其自然边界(alignment)分配空间。各成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。字节对齐的问题主要就是针对结构体。
3.2 对齐准则
先来看四个重要的基本概念:
1) 数据类型自身的对齐值:char型数据自身对齐值为1字节,short型数据为2字节,int/float型为4字节,double型为8字节。
2) 结构体或类的自身对齐值:其成员中自身对齐值最大的那个值。
3) 指定对齐值:#pragma pack (value)时的指定对齐值value。
4) 数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值}。
基于上面这些值,就可以方便地讨论具体数据结构的成员和其自身的对齐方式。