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

最近在搞个网络通信协议,

采用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 <stdio.h>
#include <string.h>
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 <stdio.h>
#include <string.h>
typedef unsigned char UINT8;
typedef unsigned short UINT16;#define MAX_FRM_DATA_LEN 100typedef struct protocol_msg_s{UINT8 msgType;UINT8 data1;UINT8 data2;UINT16 len;char data[MAX_FRM_DATA_LEN];
}PRO_MSG;int frm_parse(PRO_MSG *pmsg,UINT8 buf[],int len)
{int pos=0;pmsg->msgType = buf[pos];pos++;pmsg->data1 = buf[pos];pos++;	pmsg->data2 = buf[pos];pos++;pmsg->len = buf[pos]<<8 | buf[pos+1]<<0;pos+=2;	if(pmsg->len>MAX_FRM_DATA_LEN){printf("frm len is longer than 100\n");return -1;}memcpy(pmsg->data,&buf[pos],pmsg->len);return 0;
}
int maini(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 msg;PRO_MSG *pmsg = &msg;frm_len = sizeof(frm);ret = frm_parse(pmsg,frm,frm_len);if(ret<0){printf("frm_parse fail\n");return -1;}printf("devType:%02x data1:%02x data2:%02x len:%04x \n",pmsg->msgType,pmsg->data1,pmsg->data2,pmsg->len);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269816.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

PSVR2下个月将正式支持PC

PlayStation VR 2将于下个月正式支持PC平台。连接PC&#xff0c;需要使用PlayStation VR2头显PC适配器&#xff0c;该适配器将于8月7日发售。 需要注意的是&#xff0c;玩家还需要一根兼容DisplayPort 1.4的线缆、一个Steam账号以及满足最低配置要求的PC。 索尼特别强调&#…

js 替换json中的转义字符 \

例如有以下字符串 "\"{\\\"account\\\":\\\"66\\\",\\\"name\\\":\\\"66\\\"}\"" 想得到如下字符串 {"account":"66","name":"66"} 执行替换字符串 "\"{…

大坝安全监测设备有哪些主要功能?

推荐型号&#xff1a;TH-WY1】大坝安全监测设备的主要功能包括以下几个方面&#xff1a; 1. **实时监测大坝的各项物理参数**&#xff1a;包括应变、位移、水位、流量等<sup>1</sup><sup>2</sup>。 2. **数据处理和分析**&#xff1a;对监测数据进行处…

热门音效、BGM哪里可以免费下载?

剪辑的奇妙世界等你探索&#xff01;在这个创意的领域里&#xff0c;音效是创造氛围、增强表现力的重要元素。我整理了8个优质的剪辑音效素材网站&#xff0c;它们提供了丰富多样的音效资源&#xff0c;无论是制作视频、音乐还是动画&#xff0c;都能为你提供所需的声音。 1、b…

单关节电机动力学辨识

这是一个单关节电机的动力学辨识过程&#xff0c;这是一个yaw轴转动电机的动力学辨识过程 1、动力学建模 &#xff08;1&#xff09;整体动力学 F J α f F J\alpha f FJαf 单关节的物理量包括惯性项、离心力和科氏力、摩擦力。这里忽略离心力和科氏力&#xff0c;据说…

信息学奥赛初赛天天练-47-CSP-J2020完善程序1-质数、因数、质因数、质因数分解算法、质因数分解算法优化

PDF文档公众号回复关键字:20240727 2020 CSP-J 完善程序1 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 质因数分解给出正整数 n&#xff0c;请输出将 n 质因数分解的结果&#xff0c;结果从小到大输出 例如&#xff1a;输入 n120&#xff0c;程序应该输出…

mysql报错:Unknown collation: ‘utf8mb4_0900_ai_ci‘的原因及解决方法

参考博客&#xff1a;http://t.csdnimg.cn/NRzyk 报错场景描述 使用navicate在查询中运行sql语句时报错&#xff1a;Unknown collation: utf8mb4_0900_ai_ci 报错原因 生成转储文件的数据库版本为8.0&#xff0c;我本地数据库版本为5.6&#xff0c;高版本导入到低版本&…

【C++】透析类和对象(下)

有不懂的可以翻阅我之前文章&#xff01; 个人主页&#xff1a;CSDN_小八哥向前冲 所属专栏&#xff1a;CSDN_C入门 目录 拷贝构造函数 运算符重载 赋值运算符重载 取地址运算符重载 const成员函数 取地址重载 再探构造函数 初始化列表 类型转换 static成员 友元 内…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

(最全最小白易懂版)Yolov8新手教程-配置环境、数据集处理、目标检测、结果分析处理(图像指标、可视化结果)、报错分析等全过程学习记录

目录 一、安装环境&#xff08;配置yolo、demo测试&#xff09; 二、数据集准备&#xff08;格式学习&#xff09; 三、训练数据集 1.划分数据集 2.训练数据集 2.1常规训练 2.2微调 3.各种报错记录 3.1AttributeError 3.2TypeError 3.3Error while loading conda en…

Flutter Dio网络请求报错FormatException: Unexpected character

最近开发Flutter项目&#xff0c;网络请求采用的是Dio框架&#xff0c;在发起网络请求的时候报错&#xff1a; 网络请求返回的数据为&#xff1a; var returnCitySN {\"cip\": \"127.0.0.1\", \"cid\": \"00\", \"cname\"…

浅谈 JVM 的内存划分、类加载、垃圾回收机制

文章目录 一、JVM内存划分1.1、JVM为什么要进行内存划分&#xff1f; 二、JVM类加载2.1、什么是类加载&#xff1f;2.2、类加载大体过程2.3、何时触发类加载&#xff1f;2.4、双亲委派模型[!面试高频问题]2.4.1、类加载器2.4.1、什么是双亲委派模型&#xff1f; 三、JVM 垃圾回…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

书生大模型实战营--L1关卡-OpenCompass 评测 InternLM-1.8B 实践

一、使用 OpenCompass 评测 internlm2-chat-1.8b 模型在 MMLU 数据集上的性能 1、使用lmdeploy部署 internlm2-chat-1.8b模型 2、根据OpenCompass官网教程安装并下载数据集 opencompass/README_zh-CN.md at main open-compass/opencompass GitHub 注意&#xff1a; pyhton…

【Java】this关键字、构造方法、标准javabean类(009)

目录 ♦️构造方法 &#x1f383;无参数构造方法&#xff08;空参构造&#xff09; &#x1f383;有参数构造方法 ♦️this关键字 &#x1f383;就近原则 &#x1f383;使用this关键字调用本类中的属性 ​编辑 &#x1f383;使用this关键字调用成员方法 ​编辑 &#x…

Collention集合基础知识

Array 数组是一种连续的内存空间存储相同数据类型数据的线性数据结构 数组获取其他元素的地址值 寻址公式 a[i] baseaddress i*datatypesize 为什么数组索引从0开始 从1开始不行吗 从0开始寻址公式 a[i] baseaddress i*datatypesize 从1开始寻址公式 a[i] baseadd…

【计算机网络】无线网络和移动网络(第9章)大纲(共70+页)

最后只复习了1.5天&#xff0c;应用层简单过了一遍。 本来是mindmap的&#xff0c;但是太大了只能导出成提纲了&#xff0c;凑合看吧orz。 如果你找我要源文件&#xff0c;最好是在2024年&#xff0c;不然我可能就找不到了&#xff08;&#xff09;。

基于STC8H系列单片机的中断系统

基于STC8H系列单片机的中断系统 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单片机管脚图(20个引脚)STC8H系列单片机管脚说明STC8H系列单片机I/O口STC8H系列单片机I/O口相…

【C++】:红黑树的应用 --- 封装map和set

点击跳转至文章&#xff1a;【C】&#xff1a;红黑树深度剖析 — 手撕红黑树&#xff01; 目录 前言一&#xff0c;红黑树的改造1. 红黑树的主体框架2. 对红黑树节点结构的改造3. 红黑树的迭代器3.1 迭代器类3.2 Begin() 和 End() 四&#xff0c;红黑树相关接口的改造4.1 Find…

centos stream 9安装 Kubernetes v1.30 集群

1、版本说明&#xff1a; 系统版本&#xff1a;centos stream 9 Kubernetes版本&#xff1a;最新版(v1.30) docker版本&#xff1a;27.1.1 节点主机名ip主节点k8s-master172.31.0.10节点1k8s-node1172.31.0.11节点2k8s-node2172.31.0.12 2、首先&#xff0c;使用Vagrant和Virt…