当前位置: 首页 > news >正文

日常知识点之遇到问题结构体按位构造协议时和期望不一致,研究记录一下

遇到一个问题,在做业务的时候,涉及到协议相关,按位进行设计,用结构体来模拟协议时,发现内存存储和实际目的不一致,知道是大小端以及计算机底层存储逻辑相关,所以研究了一下。

1:简单问题描述。

如下结构,是按照用户协议解析出来的结构:

按照数据协议,总共6个字节,期望按占位3,1,1,1,5,5 ,2,20,10进行解析,这里期望的是内存中存储的值是按照结构进行存储和展示的。

//我本来构造这样对应的结构。
#pragma pack(1)
typedef struct _trans_header_t
{unsigned short version:3;  unsigned short type:1;     unsigned short vice_type:1;  unsigned short apid_tid:1; unsigned short apid_pid:5; unsigned short apid_pcat:5; unsigned int group_type:2; unsigned int trans_num:20; unsigned int trans_user_data_len:10;
}TRANS_HEADER_T;
#pragma pack()

如上,对应期望的协议,我定义了对应的结构,但是赋值时发现对不上。 (这里肯定是结构体位和对应大小端问题导致。)

2:分析一下这里位和大小端的存储。

结构体设置按字节对齐(默认或者自己设置,小端模式,按位处理实际上是从低位开始)

int main(int argc, char *argv[])
{TRANS_HEADER_T header;header.version = 1;header.type = 0;header.vice_type = 1;header.apid_tid = 0;header.apid_pid = 3;header.apid_pcat = 3;header.group_type=3;header.trans_num = 7;header.trans_user_data_len = 1;
/********************  
1101 0001       11 0 1 0 001 
0001 1000		00011  000
0001 1111  		000111 11
0000 0000		00000000
0100 0000 		01 000000 
0000 0000		00000000
*********************/for(unsigned int i=0; i<sizeof(header); i++){int num = *((unsigned char *)&header +i);qDebug() <<num<<"===>"<< QString::number(num, 2) ;}unsigned short *UTest = (unsigned short *)&header;qDebug()<<"data = "<<(*UTest); //6353     0001 1000 1101 0001unsigned int *UTest1 = (unsigned int *)((unsigned char *)&header +2);qDebug()<<"data = "<<(*UTest1); //4194335   0000 0000 0100 0000 0000 0000 0001 1111return 0;
}
//分析一下,因为按1Byte进行对齐,所以每次以1Byte进行处理,从低位开始按位赋值,当1byte不够用时,就取下一个byte,这是低位进行赋值。
//按每1byte,按照结构体定义的结构,依次赋值。
//然后大小端的问题,实际上是转成对应的unsigned short和unsigned int时取值时生效的。

3:疑问以及总结

疑问:本想按照定义的结构给结构体赋值,发现赋值后期望结果和预期不一致。

总结:其实核心还是按位处理,按位处理时是从低位往高位写。

处理:

方案1:我直接抛弃这种方案,采用字节|的方式。

(这里注意数值的写入是以内存中存的值为准,按值进行设置的数据,需要按内存进行大小端处理)

	//short +unsigned intunsigned short version_apid = 0;unsigned int flag_and_len = 0;// 000 1 0 010 001 9+i 前6位固定   0001 00 激光载荷10001 文件 9+iif(!m_is_reTrans){version_apid |= 0x1220; // 0001 0010}else{version_apid |= 0x1620; // 0001 0110}version_apid |= 9+i;//分组标识和对应的数据长度flag_and_len |= 0xC0000000;flag_and_len |= arr.size()-1;dst_arr.resize(8+arr.size());dst_arr.fill(0);version_apid = short_host_to_network(version_apid);flag_and_len = int_host_to_network(flag_and_len);bool IsBigEndian()
{short a = 0x1234;char b = *(char*)&a;if (0x12 == b) //高位存储在低地址处  是大端{return true;}return false; //否则   高位存储在高地址位  小端模式
}unsigned int int_host_to_network(unsigned int number)
{bool flag = IsBigEndian();if (flag) //大端模式  不用处理{return number;}unsigned int data = number;unsigned char* abyte0 = (unsigned char*)&data;// 小端模式if (!flag) //如果电脑是小端模式  需要处理成大端模式{abyte0[0] = (unsigned char)((0xff000000 & number) >> 24);abyte0[1] = (unsigned char)((0x00ff0000 & number) >> 16);abyte0[2] = (unsigned char)((0x0000ff00 & number) >> 8);abyte0[3] = (unsigned char)(0x000000ff & number);}return data;
}unsigned short short_host_to_network(unsigned short number)
{bool flag = IsBigEndian();if (flag) //大端模式  不用处理{return number;}unsigned short data = number;unsigned char* abyte0 = (unsigned char*)&data;// 小端模式 //需要进行处理if (!flag){abyte0[0] = (unsigned char)((0xff00 & number) >> 8);abyte0[1] = (unsigned char)(0x00ff & number);}return data;
}

方案二:

按照结构体的思路,对结构体进行处理使其符合。 (一般协议设计以8位为准(这种容易处理,结构体定义时和协议反转就好),这里比较复杂,用到16位,32位,思考测试有没有可用方案。)

如果是大端,理论上按协议定义结构体是没问题的,从高位往低位,位依次存储(未验证)

如果是小端,按位存储,实际上是从低位往高位,比如1byte从后往前写。

​ ===》如果结构体协议位刚好凑够8位,则对结构体进行反转即可。

​ ===》如果类似如下的结构,大端模式理论直接赋值可以,小端模式复杂化,没想到对应方案。

//如果位拼接刚好满足1byte 8位,则以1byte进行结构体反转能适配到协议吧。
//这里位刚好凑到16位,32位,需要根据大小端和结构体做适配吧。      
//如果是大端,理论上按协议定义结构体是没问题的,从高位往低位,位依次存储(未验证)
//如果是小端,需要自己处理,这里能想到的是,对结构体进行适配,如下,赋值后进行大小端转换是否可行?    
//     按位存储是从低位往高位存储,如下对按照协议,这样赋值,测试后发现  也是不合理的 
#pragma pack(1)
typedef struct _trans_header_t
{unsigned short apid_pcat:5; //源包的名称unsigned short apid_pid:5; //产生源包的设备 unsigned short apid_tid:1; //重传标志 默认为0unsigned short vice_type:1;  //副导头   0bunsigned short type:1;     //1B   遥控源包unsigned short version:3;  //000Bunsigned int trans_user_data_len:10;unsigned int trans_num:20; //对相同apid进行计数 初始值为0    如果源包文件小于875字节   填0unsigned int group_type:2; //分组标识  固定11b
}TRANS_HEADER_T;
#pragma pack()

总结:

如果是小端,结构体处理时是从低位往高位依次存储,从后往前。

如果是大端,结构体处理时时从高位往低位依次存储,按位从前往后。

在用结构体处理协议时,需要注意协议构造和处理的两端对应即可,特定的不满足1byte或者其倍数的协议,按位处理时要注意写入位置。

相关文章:

日常知识点之遇到问题结构体按位构造协议时和期望不一致,研究记录一下

遇到一个问题&#xff0c;在做业务的时候&#xff0c;涉及到协议相关&#xff0c;按位进行设计&#xff0c;用结构体来模拟协议时&#xff0c;发现内存存储和实际目的不一致&#xff0c;知道是大小端以及计算机底层存储逻辑相关&#xff0c;所以研究了一下。 1&#xff1a;简单…...

spring mvc 文件下载

在web中下载的方式大多基于servlet&#xff0c;在web.xml中配置下载路径&#xff0c;这里再介绍json(转成base64字符串)和blob的使用方式 servlet WEB-INF/web.xml <!--url映射--> <servlet-mapping><servlet-name>DowloadServlet</servlet-name>&l…...

Qt WebEngine基于WebEngineScript注入js脚本

在之前的文章中&#xff0c;我们介绍了Qt WebEngine注入js的用法&#xff0c;及runJavaScript()的用法&#xff0c;该方法主要是用在页面加载完成后&#xff0c;为了和网页做一些交互时使用。有时候需要监听网页加载完成的一些状态或信息&#xff0c;则需要网页加载前注入js来实…...

案例分享-国外UI设计界面赏析

国外UI设计倾向于简洁的布局和清晰的排版&#xff0c;减少视觉干扰&#xff0c;提升用户体验。通过合理的色彩搭配和图标设计&#xff0c;营造舒适愉悦的使用氛围。 设计师不拘泥于传统框架&#xff0c;勇于尝试新元素和理念&#xff0c;使界面独特有趣。同时&#xff0c;强调以…...

用PyTorch 从零开始构建 BitNet 1.58bit

我们手动实现BitNet的编写&#xff0c;并进行的一系列小实验证实&#xff0c;看看1.58bit 模型是否与全精度的大型语言模型相媲美&#xff01; 什么是量化以及为什么需要它&#xff1f; 量化是用更少的比特数表示浮点数的过程。当两个数字使用不同的比特数进行量化时&#xf…...

信创安全 | 新一代内网安全方案—零信任沙盒

在当今数字化时代&#xff0c;访问安全和数据安全成为企业面临的重要挑战。传统的边界防御已经无法满足日益复杂的内网办公环境&#xff0c;层出不穷的攻击手段已经让市场单一的防御手段黔驴技穷。当企业面临越来越复杂的网络威胁和数据泄密风险时&#xff0c;更需要一种综合的…...

Redis的回收策略(淘汰策略)

volatile-lru &#xff1a;从已设置过期时间的数据集&#xff08; server.db[i].expires &#xff09;中挑选最近最少使用的数据淘汰 volatile-ttl &#xff1a; 从已设置过期时间的数据集&#xff08; server.db[i].expires &#xff09; 中挑选将要过期的数据淘汰 volatile…...

Electron-builder 打包

项目比较简单&#xff0c;仅使用了 Electron 原生js 安装 electron-builder npm install electron-builder --dev配置 package.json 中的打包命令 {"script":{// ..."dev": "electron .","pack": "electron-builder"} }添…...

笔试练习day3

目录 BC149 简写单词题目解析代码 dd爱框框题目解析解析代码方法一暴力解法方法二同向双指针(滑动窗口) 除2!题目解析解法模拟贪心堆 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412; 个人主页 &#x1f978;&#x1…...

企业想要将大模型技术应用到企业管理中需具备什么条件?

#企业 #企业管理 #大模型 企业想要将大模型技术应用到企业管理中&#xff0c;需要考虑以下几个关键条件&#xff1a; 1.明确的需求定位&#xff1a;企业应首先诊断自身的业务场景、数据、算法、基础设施预算以及战略等能力&#xff0c;明确大模型能够为企业带来的具体赋…...

go 事件机制(观察者设计模式)

背景&#xff1a; 公司目前有个业务&#xff0c;收到数据后&#xff0c;要分发给所有的客户端或者是业务模块&#xff0c;类似消息通知这样的需求&#xff0c;自然而然就想到了事件&#xff0c;观察者比较简单就自己实现以下&#xff0c;确保最小功能使用支持即可&#xff0c;其…...

RISC-V竞赛|第二届 RISC-V 软件移植及优化锦标赛报名正式开始!

目录 赛事背景 赛道方向 适配夺旗赛 优化竞速赛 比赛赛题&#xff08;总奖金池8万元&#xff01;&#xff09; &#x1f525;竞速赛 - OceanBase 移植与优化 比赛赛程&#xff08;暂定&#xff09; 赛事说明 「赛事背景」 为了推动 RISC-V 软件生态更快地发展&#xff0…...

【VTK】ubuntu手动编译VTK9.3 Generating qmltypes file 失败

环境 硬件&#xff1a;Jetson Xavier NX 套件 系统&#xff1a;Ubuntu 20.04 软件 &#xff1a;QT5.15.6 解决 0、问题 最近在Jetson Xavier NX 套件上编译VTK库&#xff0c;因为想要配合QQuick使用&#xff0c;所以cmake配置时勾选了VTK_MODULE_ENABLE_VTK_GUISupportQtQu…...

学习java的日子 Day64 学生管理系统 web2.0 web版本

MVC设计模式 概念 - 代码的分层 MVC&#xff1a;项目分层的思想 字母表示层理解MModle模型层业务的具体实现VView视图层展示数据CController控制器层控制业务流程&#xff08;跳转&#xff09; 1.细化理解层数 Controller&#xff1a;控制器层&#xff0c;用于存放Servlet&…...

【第14章】Spring Cloud之Gateway路由断言(IP黑名单)

文章目录 前言一、内置路由断言1. 案例&#xff08;Weight&#xff09;2. 更多断言 二、自定义路由断言1. 黑名单断言2. 全局异常处理3. 应用配置4. 单元测试 总结 前言 Spring Cloud Gateway可以让我们根据请求内容精确匹配到对应路由服务,官方已经内置了很多路由断言,我们也…...

3、pnpm yarn npm

项目里实际上就只有这些依赖 node module 里却有很多的包 原因&#xff1a; 比如说vue&#xff0c;vue内部有依赖了其余的包。工具又依赖了别的依赖 造成的问题&#xff1a;我可以直接去用这个包&#xff0c;但是这个包在package.json中却没有看到-----幽灵依赖 那如果说别…...

❄️5. Kubernetes核心资源之名称空间和Pod实战

**什么是名称空间Namespace: ** Namespace是k8s系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多用户的资源隔离。默认情况下&#xff0c;k8s集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互…...

锂电池充电板电路设计

写这篇文章的目的主要是个人经验的总结&#xff0c;希望能给开发者们提供一种锂电池充电电路以及电源显示的电路思路。接下来从以下几个方面讲述电路。 设计这款电路的初衷是想用一块硬币大小的锂电池作为供电电源&#xff08;3.5V-4.2V&#xff09;&#xff0c;降压供给3.3V电…...

工业互联网产教融合实训基地解决方案

一、引言 随着“中国制造2025”战略的深入实施与全球工业4.0浪潮的兴起&#xff0c;工业互联网作为新一代信息技术与制造业深度融合的产物&#xff0c;正引领着制造业向智能化、网络化、服务化转型。为培养适应未来工业发展需求的高素质技术技能人才&#xff0c;构建工业互联网…...

高效批量提取PPT幻灯片中图片的方法

处理包含大量图片的PPT&#xff08;PowerPoint&#xff09;幻灯片已成为许多专业人士的日常任务之一。然而&#xff0c;手动从每张幻灯片中逐一提取图片不仅耗时耗力&#xff0c;还容易出错。为了提升工作效率&#xff0c;减少重复劳动&#xff0c;探索并实现一种高效批量提取P…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...