手撕代码: C++实现按位序列化和反序列化

目录

1.需求

2.流程分析

3.实现过程

4.总结


1.需求

        在我们正在开发的项目,有这样一种需求,实现固定格式自由格式比特流无线传输。解释一下,固定格式形如下面表格:

每个字段都有位宽、类型等属性,这种固定格式一般总位宽都是固定的,比如72比特(9个字节)。它的序列化过程就是把比特数据转换成字节流,反序列化过程即是把字节流转换成比特数据。

自由格式形如下面表格:

它的最大位宽是固定的,但是总位宽是不固定的,用户可以自定义每个字段;自定义格式的序列化和反序列化跟固定格式的流程是差不多的。

2.流程分析

以下面自定义格式为例来说明实现的过程:

自定义格式的组包过程如下:

1)字段1为2个比特,值为1,二进制为0b00000001,即把0b01移到第1个字节的低两位。

2)字段2为5个比特,值为5,二进制为0b00000101,即把0b00101移到第1个字节的第2位到第6位。

3)字段3为3个比特,值为2,二进制为0b00000010,即把0b010的最低比特0移到第1个字节的第7位,高两个比特01移到第2字节的低两位上。

4)字段4、字段5、字段6依次做类似处理。

5)这个自定义格式总共36个比特,比5个字节(40个比特)还少4个比特,把最后一个字节高4个比特填充0,于是得到字节流如上图的底部所示。

解包过程即是上面的流程反过来,就不在这里赘述了。

3.实现过程

单个字段组包实现过程代码如下:

int CJField::getData(char* pData, int len, int& currIndex, int& reserveBit) const {constexpr quint8 nShift[] = { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };int nBitWidth = m_bitWidth;qint64 value = m_value;if (reserveBit <= 0) {currIndex++;reserveBit = 8;}while (nBitWidth > 0) {if (nBitWidth > reserveBit) {pData[currIndex] |= ((value & nShift[reserveBit - 1]) << (8 - reserveBit));value >>= reserveBit;currIndex++;nBitWidth -= reserveBit;reserveBit = 8;}else {pData[currIndex] |= ((value & nShift[nBitWidth - 1]) << (8 - reserveBit));reserveBit -= nBitWidth;nBitWidth = 0;}}return 1;
}

单个字段解包实现过程代码如下:

int  CJField::setData(const char* pData, int len, int& currIndex, int& reserveBit) {constexpr quint8 nShift[] = { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };int nBitWidth = m_bitWidth;qint64 value = 0;if (reserveBit <= 0) {currIndex++;reserveBit = 8;}while (nBitWidth > 0) {if (nBitWidth > reserveBit) {value |= ((qint64)((pData[currIndex] >> (8 - reserveBit)) & nShift[reserveBit - 1]) << (m_bitWidth - nBitWidth));nBitWidth -= reserveBit;reserveBit = 8;currIndex++;}else {value |= ((qint64)((pData[currIndex] >> (8 - reserveBit)) & nShift[nBitWidth - 1]) << (m_bitWidth - nBitWidth));reserveBit -= nBitWidth;nBitWidth = 0;}}m_value = value;calcPhyFromValue();return 1;
}

自定义格式整体组包过程代码如下:

    /// <summary>/// //组包/// </summary>/// <param name="pData"></param>/// <param name="nLen"></param>/// <returns></returns>int getData(char* pData, int& nLen) {int  nCurrIndex = 0;int  nReserveBit = 8;//[1]if (m_vecMsgFields.size() <= 0)return 0;//[2]for (auto& it : m_vecMsgFields) {it->getData(pData, nLen, nCurrIndex, nReserveBit);}//[3]填充数据,长度为9的倍数nLen = nCurrIndex + 1;while (nLen % 9 != 0) {nLen++;}return 1;}

自定义格式整体解包过程代码如下:

    /// <summary>/// 解包/// </summary>/// <param name="pData"></param>/// <param name="nLen"></param>/// <returns></returns>int setData(const char* pData, int nLen) {int  nCurrIndex = 0;int  nReserveBit = 8;//[1]if (m_vecMsgFields.size() <= 0)return 0;//[2] 根据模板,解析内容for (auto& it : m_vecMsgFields) {it->setData(pData, nLen, nCurrIndex, nReserveBit);}return 1;}

固定格式和自由格式的实现差不多,就不在这里赘述了。

4.总结

        上述实现的按位序列化和反序列化的过程并不是很复杂;看着上面的过程,可以自己动手写写其实现过程,就会真正理解它。

        你要相信一句话:纸上得来终觉浅,绝知此事要躬行。

        如果需要此实现的详细源代码,可以后台@我。

推荐阅读

手撕代码: C++实现数据的序列化和反序列化_c++序列化和反序列化实例-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Rust自学】12.6. 使用TDD(测试驱动开发)开发库功能

12.6.0. 写在正文之前 第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print)&#xff0c;是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。 这个项目分为这么几步&#xff1a; 接收命令行参数读取…

C#,入门教程(27)——应用程序(Application)的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(26)——数据的基本概念与使用方法https://blog.csdn.net/beijinghorn/article/details/124952589 一、什么是应用程序 Application&#xff1f; 应用程序是编程的结果。一般把代码经过编译&#xff08;等&#xff09;过程&#…

机器学习(1):线性回归概念

1 线性回归基础 1.1 什么是线性 例如&#xff1a;汽车每小时60KM&#xff0c;3小时可以行使多长距离&#xff1f;已知汽车的速度&#xff0c;则汽车的行使距离只与时间唯一相关。在二元的直角坐标系中&#xff0c;描出这一关系的图是一条直线&#xff0c;所以称为线性关系。 线…

日志系统实践

日志系统 产生日志 logging:level:root: infoconfig: /usr/src/config/logback-spring.xml<?xml version"1.0" encoding"UTF-8"?> <configuration><appender name"STDOUT" class"ch.qos.logback.core.ConsoleAppender&qu…

基于微信小程序的智能停车场管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

如何选择Ubuntu版本

一、为什么要选择Ubuntu系统&#xff1f; CentOS官方已全面停止维护CentOS Linux项目 。具体来说&#xff0c;CentOS 8已于2021年12月31日停止维护&#xff0c;而CentOS 7则在2024年6月30日结束了生命周期 。这意味着这些版本不再接收官方的安全更新、bug修复或技术支持 二、…

Elasticsearch ES|QL 地理空间索引加入纽约犯罪地图

可以根据地理空间数据连接两个索引。在本教程中&#xff0c;我将向你展示如何通过混合邻里多边形和 GPS 犯罪事件坐标来创建纽约市的犯罪地图。 安装 如果你还没有安装好自己的 Elasticsearch 及 Kibana 的话&#xff0c;请参考如下的链接来进行安装。 如何在 Linux&#xff0…

分布式缓存redis

分布式缓存redis 1 redis单机&#xff08;单节点&#xff09;部署缺点 &#xff08;1&#xff09;数据丢失问题&#xff1a;redis是内存存储&#xff0c;服务重启可能会丢失数据 &#xff08;2&#xff09;并发能力问题&#xff1a;redis单节点&#xff08;单机&#xff09;部…

【ArcGIS初学】产生随机点计算混淆矩阵

混淆矩阵&#xff1a;用于比较分类结果和地表真实信息 总体精度(overall accuracy) :指对角线上所有样本的像元数(正确分类的像元数)除以所有像元数。 生产者精度(producers accuracy) &#xff1a;某类中正确分类的像元数除以参考数据中该类的像元数(列方向)&#xff0c;又称…

C++ STL之容器介绍(vector、list、set、map)

1 STL基本概念 C有两大思想&#xff0c;面向对象和泛型编程。泛型编程指编写代码时不必指定具体的数据类型&#xff0c;而是使用模板来代替实际类型&#xff0c;这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C泛型编程的一个杰出例子。STL&#xff08;Standard …

GitLab本地服务器配置ssh和克隆项目

1. 本地安装好git git链接&#xff1a;https://git-scm.com/downloads/win 无脑点击下一步安装即可,打开Git Bash命令终端如下&#xff1a; 2. 配置本地用户名和邮箱 git config --global user.name "你的名字" git config --global user.email "你的邮箱&quo…

【Unity高级】一文了解Unity 中的条件编译(附所有指令)

一、Unity中的条件编译 Unity 对 C# 语言的支持包括使用指令&#xff0c;这些指令允许您根据是否定义了某些脚本符号&#xff0c;选择性地包含或排除代码的编译。有关这些指令在 C# 中如何工作的更多信息&#xff0c;请参阅微软关于 C# 预处理器指令 的文档。 &#xff08;一…

主数据系统建设模式分析

很多企业在长期的信息化建设和使用过程中&#xff0c;或多或少的存在数据一致性问题&#xff0c;这类问题导致了大量的数据手工梳理、清洗的工作&#xff0c;对于系统的对接以及统计分析造成了极大的不便&#xff0c;因此信息化部门的管理者迫切的想通过主数据项目来解决目前的…

Redis是单线程还是多线程?

大家好&#xff0c;我是锋哥。今天分享关于【Redis是单线程还是多线程&#xff1f;】面试题。希望对大家有帮助&#xff1b; Redis是单线程还是多线程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis是 单线程 的。 尽管Redis的处理是单线程的&a…

UML系列之Rational Rose笔记一:用例图

好久没有更新笔记了&#xff1b;最近想整理下近期掌握的UML软件建模的知识笔记&#xff1b; 包括但不限于Rational Rose&#xff1b;Drawio&#xff1b;EA&#xff1b;PowerDesigner&#xff1b;Visio&#xff1b;StarUML&#xff1b;Software等软件的使用&#xff1b;UML软件…

熵权法(变异系数法)

熵权法(变异系数法) 一种客观赋权方法&#xff0c;它根据指标的变异程度来确定指标的权重&#xff0c;变异程度越大&#xff0c;说明该指标所包含的信息量越大&#xff0c;相应的权重也就越大。以下是熵权法的详细介绍&#xff1a; 概率与信息量的关系 概率P(x)越小,信息量I(…

基于当前最前沿的前端(Vue3 + Vite + Antdv)和后台(Spring boot)实现的低代码开发平台

项目是一个基于当前最前沿的前端技术栈&#xff08;Vue3 Vite Ant Design Vue&#xff0c;简称Antdv&#xff09;和后台技术栈&#xff08;Spring Boot&#xff09;实现的低代码开发平台。以下是对该项目的详细介绍&#xff1a; 一、项目概述 项目名称&#xff1a;lowcode-s…

JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南

1、简述 在支付系统中&#xff0c;订单支付的超时自动撤销是一个非常常见的业务场景。通常用户未在规定时间内完成支付&#xff0c;系统会自动取消订单&#xff0c;释放相应的资源。本文将通过利用 RabbitMQ 的 死信队列&#xff08;Dead Letter Queue, DLQ&#xff09;来实现…

逻辑测试题

https://blog.csdn.net/qq_39081315/article/details/121393597 先生成一个点&#xff0c;每生成一个点判断距离&#xff0c;角度&#xff0c;满足加入存点的容器&#xff0c;直到容器大小为4。 随机生成点&#xff1a; 分区域&#xff1a;最大距离20&#xff0c;以20为正方形…

图解Git——分支开发工作流《Pro Git》

分支开发工作流 由于分支管理的便捷&#xff0c; 才衍生出这些典型的工作模式&#xff0c;你可以根据项目实际情况选择。 1. 长期分支 适用于持续开发和发布周期长的项目。常见的长期分支包括&#xff1a; master&#xff1a;只保留稳定的代码&#xff0c;通常用于生产环境。…