专栏名称: 嵌入式微处理器
关注这个时代最火的嵌入式微处理器,你想知道的都在这里。
目录
相关文章推荐
重庆校园频道  ·  2025年全国中小学生英语作文征集活动正式启 ... ·  22 小时前  
重庆校园频道  ·  2025年全国中小学生英语作文征集活动正式启 ... ·  22 小时前  
玺承电商观察  ·  从CORE新流量机制到付费投流,多维度教你在 ... ·  23 小时前  
玺承电商观察  ·  从CORE新流量机制到付费投流,多维度教你在 ... ·  23 小时前  
中国能源报  ·  关于举办绿电、绿证、CCER交易培训的通知 ·  昨天  
田俊国讲坛  ·  【2025重磅来袭】业务赋能导师特训营|直面 ... ·  2 天前  
最江阴  ·  最新消息,每人可省500元! ·  3 天前  
51好读  ›  专栏  ›  嵌入式微处理器

由字节对齐引发的一场“血案“

嵌入式微处理器  · 公众号  ·  · 2024-07-30 12:00

正文


最近在搞个网络通信协议, 采用socket udp传输, 运行时居然报段错误了。 经过debug,发现居然是因为字节对齐问题导致的。

这个问题在实现通信协议,是经常会遇到的问题。 为了方便读者理解, 我把内容做了简化,分享给大家。

1、协议说明

通信协议信令格式如下:

typedef struct protocol_msg_s{
 UINT8 msgType;
 UINT8 data1;
 UINT8 data2;
 UINT16 len;
 char data[100];
}PRO_MSG;

根据协议格式,我造了一个数据frm,代表我收到的某个信令,

 UCHAR frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07};

根据协议, 信令的字段与原始帧对应关系如下:

于是,我实现了一个简单的解析代码【该代码有问题】。

int main(int argc, char **argv)
{
 int ret;
 int frm_len = 0;
 UINT8 frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07};


 PRO_MSG *pmsg = (PRO_MSG *)frm;

 printf("devType:%02x data1:%02x data2:%02x len:%04x \n",
   pmsg->msgType,
   pmsg->data1,
   pmsg->data2,
   pmsg->len);
}

编译运行后,其中len的值居然是 0107 ,而不是 0007

这其实就是因为编译器采用了字节对齐导致的,

在给 pmsg->len 赋值时,因为需要2个字节,

这两个字节是 frm[3]、frm[4] 这正好分布在两个字里,

编译器忽略了 frm[3] ,最终将 frm[4]、frm[5] 合在一起赋值给了 pmsg->len

为什么有字节对齐?

简单的说内存对齐能够提高 cpu 读取数据的速度,减少 cpu 访问数据的出错性(有些 cpu 必须内存对齐,否则指针访问会出错)。

原因找打了,下面就是解决了。

2、解决办法

1. 方法1 #pragma pack()

该预处理指令用来改变对齐参数。在缺省情况下,C编译器为每一个变量或数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对齐参数:

使用伪指令#pragma pack (n),C编译器将按照n字节对齐。

使用伪指令#pragma pack (),取消自定义字节对齐方式。

完整代码:

#include 
#include 
typedef unsigned char UINT8;
typedef unsigned short UINT16;

#define MAX_FRM_DATA_LEN 100
#pragma pack(1)
typedef struct protocol_msg_s{
 UINT8 msgType;
 UINT8 data1;
 UINT8 data2;
 UINT16 len;
 char data[MAX_FRM_DATA_LEN];
}PRO_MSG;
#pragma
int main(int argc, char **argv)
{
 int ret;
 int frm_len = 0;
 UINT8 frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07};

 PRO_MSG *pmsg = (PRO_MSG *)frm;

 printf("devType:%02x data1:%02x data2:%02x len:%04x \n",
   pmsg->msgType,
   pmsg->data1,
   pmsg->data2,
   pmsg->len);
}

2. 方法2

老老实实将收到的数据帧逐字节解析,

并填充到 struct protocol_msg_s

#include 
#include 
typedef unsigned char






请到「今天看啥」查看全文