如何在C++中实现按位存取

在我创业的一个项目中,为了节约网络带宽,因此在网络中传输数据需要实现紧凑存取,在国防,科研,航天,军工等多个领域其实也有类似的需求。
实现紧凑存取,不是按一个字节一个字节地存取,而是按位存取。比如一个字节,我们可以存储8个bool信息,废话少说,直接分享代码(备注:里面的代码算法值得优化)。

//以下为函数定义

/***********************************************************************/
/*  函数作用:从buffer读一个位                    */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数nStart[in]:指定位置                     */
/*  参数nEnd[out]:返回结束位置                    */
/*  参数retByte[out]:返回读取结果值                 */
/*  返回:void                              */
/***********************************************************************/
void ReadOneBit( byte* pBuffer, int nStart, /* out */int& nEnd, /* out */ byte& retByte ); 

/***********************************************************************/
/*  函数作用:从指定buffer里读任意一段位置数据            */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数nStart[in]:指定位置                     */
/*  参数btLength[in]:读取长度                    */
/*  参数nEnd[out]:返回结束位置                    */
/*  参数retData[out]:返回读取结果值,支持任意数据类型        */
/*  返回:void                              */
/***********************************************************************/
template<typename T>
void ReadDataFromBuffer( byte* pBuffer, int nStart, byte btLength, /* out */int& nEnd, /* out */ T& retData ); 

/***********************************************************************/
/*  函数作用:从指定buffer里读取一段字符串              */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数nStart[in]:指定位置                     */
/*  参数nCount[in]:字符串长度                    */
/*  参数nEnd[out]:返回结束位置                    */
/*  参数pRetData[out]:返回读取字符串结果               */
/*  返回:void                              */
/***********************************************************************/
void ReadStringFromBuffer( byte* pBuffer, int nStart, int nCount, /* out */int& nEnd, /* out */char* pRetData ); 

/***********************************************************************/
/*  函数作用:向buffer写一个位                    */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数btData[in]:需要写入的值                   */
/*  参数nStart[in]:指定位置                     */
/*  参数nEnd[out]:返回结束位置                    */
/*  返回:void                              */
/***********************************************************************/
void WriteOneBit( byte* pBuffer, byte btData, int nStart, /* out */int& nEnd ); 

/***********************************************************************/
/*  函数作用:向指定buffer里写入任意一段数据             */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数tData[in]:需要写入的数据,支持任意数据类型          */
/*  参数nStart[in]:指定位置                     */
/*  参数btLength[in]:读取长度                    */
/*  参数nEnd[out]:返回结束位置                    */
/*  返回:void                              */
/***********************************************************************/
template<typename T>
void WriteDataToBuffer( byte* pBuffer, T tData, int nStart, byte btLength, /* out */int& nEnd ); 

/***********************************************************************/
/*  函数作用:向指定buffer里写取一段字符串              */
/*  参数pBuffer[in]:指定buffer                    */
/*  参数pchar[in]:需要写入的字符串                  */
/*  参数nStart[in]:指定位置                     */
/*  参数nCount[in]:字符串长度                    */
/*  参数nEnd[out]:返回结束位置                    */
/*  返回:void                              */
/***********************************************************************/
void WtriteStringToBuffer( byte* pBuffer, char* pchar, int nStart, int nCount, /* out */int& nEnd ); 

//以下为函数实现

void ReadOneBit( byte* pBuffer, int nStart, /* out */int& nEnd, /* out */ byte& retByte )
{
  byte btData = pBuffer[nStart/8];
  btData = btData << nStart%8;
  retByte = btData >> 7;
  nEnd = nStart+1;
} 

template<typename T>
void ReadDataFromBuffer( byte* pBuffer, int nStart, byte btLength, /* out */int& nEnd, /* out */ T& retData )
{
  //顺序读位
  retData = 0;
  if ( btLength > sizeof(T)*8 )
    return ; 

  byte btData;
  T tData;
  while ( btLength-- )
  {
    ReadOneBit(pBuffer, nStart, nStart, btData);
    tData = btData << btLength;
    retData |= tData;
  } 

  nEnd = nStart;
} 

void ReadStringFromBuffer( byte* pBuffer, int nStart, int nCount, /* out */int& nEnd, /* out */char* pRetData )
{
  for ( int nIndex=0; nIndex<nCount; nIndex++ )
  {
    ReadDataFromBuffer(pBuffer, nStart, 8, nStart, pRetData[nIndex]);
  }
  nEnd = nStart;
} 

void WriteOneBit( byte* pBuffer, byte btData, int nStart, /* out */int& nEnd )
{
  int nSet = nStart / 8;
  byte c = pBuffer[nSet];
  switch ( btData )
  {
  case 1:
    c |= ( 1 << (7- nStart % 8) );
    break;
  case 0:
    c &= ( ~(1 << (7- nStart % 8) ) );
    break;
  default:
    return;
  }
  pBuffer [nSet] = c;
  nEnd = nStart +1;
} 

template<typename T>
void WriteDataToBuffer( byte* pBuffer, T tData, int nStart, byte btLength, /* out */int& nEnd )
{
/* //大端机模式
  byte btDataLength = sizeof(T);
  if ( btLength > sizeof(T)*8 )
    return; 

  int nDataStart = 0; //数据的第一位位置为0,顺序写入
  while ( btLength-- )
  {
    byte bitData;
    ReadOneBit((byte*)&tData, nDataStart, nDataStart, bitData);
    WriteOneBit(pBuffer, bitData, nStart, nStart);
  } 

  nEnd = nStart;
*/ 

  //小端机模式:写buffer的时候,不能顺序写位 

  //获得模版占用字节大小
  byte btDataLength = sizeof(T); 

  //校验长度是否越界
  if ( btLength > sizeof(T)*8 )
    return; 

  //将待写数据转为byte*
  byte* ptData = (byte*)&tData;  

  //求模与余
  int nSet = btLength / 8;
  int nRin = btLength % 8; 

  //定义字节数据与位数据
  byte bitData;
  byte byteData;
  int nTempEnd; 

  //先写rin数据
  byteData = ptData[nSet];
  while ( nRin-- )
  {
    ReadOneBit(&byteData, 7-nRin, nTempEnd, bitData);
    WriteOneBit(pBuffer, bitData, nStart, nStart);
  } 

  //再写Set数据
  while ( nSet )
  {
    byteData = ptData[--nSet];
    //写一个byte
    int i=0;
    while ( i!=8 )
    {
      ReadOneBit(&byteData, i++, nTempEnd, bitData);
      WriteOneBit(pBuffer, bitData, nStart, nStart);
    }
  }
  nEnd = nStart; 

} 

void WtriteStringToBuffer( byte* pBuffer, char* pchar, int nStart, int nCount, /* out */int& nEnd )
{
  for ( int nIndex=0; nIndex<nCount; nIndex++ )
  {
    WriteDataToBuffer(pBuffer, pchar[nIndex], nStart, 8, nStart);
  }
  nEnd = nStart;
}

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • C++按位异或运算符的使用介绍

    参与运算的两个值,如果两个相应位相同,则结果为0,否则为1.即:0^0=0, 1^0=1, 0^1=1, 1^1=0 例如:10100001^00010001=10110000 0^0=0,0^1=1 0异或任何数=任何数 1^0=1,1^1=0 1异或任何数-任何数取反 任何数异或自己=把自己置0 (1)按位异或可以用来使某些特定的位翻转,如对数10100001的第2位和第3位翻转,可以将数与00000110进行按位异或运算. 10100001^00000110=10100111 //1010

  • C++实现string存取二进制数据的方法

    本文实例讲述了C++实现string存取二进制数据的方法,分享给大家供大家参考.具体方法分析如下: 一般来说,STL的string很强大,用起来也感觉很舒服,这段时间在代码中涉及到了用string存取二进制数据的问题,这里记录一下,以供以后参考. 首先提一下STL中string的参考资料:http://www.cplusplus.com/reference/string/string/ ,不懂的朋友可以看下. 在数据传输中,二进制数据的buffer一般用系统预设的大数组进行存储,而不是STL的s

  • 如何在C++中实现按位存取

    在我创业的一个项目中,为了节约网络带宽,因此在网络中传输数据需要实现紧凑存取,在国防,科研,航天,军工等多个领域其实也有类似的需求. 实现紧凑存取,不是按一个字节一个字节地存取,而是按位存取.比如一个字节,我们可以存储8个bool信息,废话少说,直接分享代码(备注:里面的代码算法值得优化). //以下为函数定义 /***********************************************************************/ /* 函数作用:从buffer读一个位

  • 实例学习如何在ASP中调用DLL

    本文通过VB5.0创建ActiveX DLL文件,这个文件模拟了一个掷色子的过程,向大家介绍如何在ASP中调用DLL的文章专题. 动态联接库(DLL)是加快应用程序关键部分的执行速度的重要方法,但有一点恐怕大部分人都不知道,那就是在ASP文件也能通过调用DLL来加快服务器的执行速度,下面我简单的介绍一下在ASP文件调用DLL的步骤.  首先,必须得有DLL文件,本例是通过VB5.0创建ActiveX DLL文件,这个文件模拟了一个掷色子的过程.  在VB5.0的环境下,新建一个工程,并双击新建工

  • 如何在python中实现随机选择

    这篇文章主要介绍了如何在python中实现随机选择,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 想从一个序列中随机抽取若干元素,或者想生成几个随机数. random 模块有大量的函数用来产生随机数和随机选择元素.比如,要想从一个序列中随机的抽取一个元素,可以使用random.choice() : >>> import random >>> values = [1, 2, 3, 4, 5, 6] >>>

  • Python脚本如何在bilibili中查找弹幕发送者

    总所周知bilibili是没有办法直接查看弹幕的发送者的,这使得当我们看到一些nt弹幕的时候虽然生气,却无可奈何,但是B站是可以屏蔽某个用户发送的弹幕的,这说明数据接口里肯定有用户信息,由于最近在学爬虫,所以我想先找找弹幕接口,分析下里面的数据. 找接口 找接口当然是随便打开一个视频然后F12啦,可是当我找了两圈后我傻眼了,没找到啊..得,不能把时间浪费在这种事情上,果断打开百度,不出所料,找到了如下的两个接口,都是XML格式网页 https://comment.bilibili.com/+ci

  • 如何在springboot中使用定时任务

    在日常的开发过程中经常使用到定时任务,在springMVC的开发中,经常和quartz框架进行集成使用,但在springboot中没有这么做,而是使用了java的线程池来实现定时任务. 一.概述 在springboot中使用定时任务非常简单,只需要简单的几步即可完成. 二.详述 在springboot中要使用定时任务,首先要保证环境是springboot的,这里使用的是springboot-2.1.2.release版本.在启动类上加@EnableScheduling注解,如下, package

  • 如何在C#中使用OpenCV(GOCW使用教程)

    1.什么是GOCW 为了解决在Csharp下编写OpenCV程序的问题,我做过比较深入的研究,并且实现了高效可用的方法GreenOpenCsharpWrapper(GOCW).通过这种方法,能够分离界面和算法业务,高效率完成算法调用,而且非常方便进行算法维护.应该说是我在多年项目实践中不断总结提炼出来的一点东西.        GOCW的发布地址为:https://gitee.com/jsxyhelu2020/gocw 2.GOCW有什么特点 分离界面和算法业务 图像数据直接通过内存传值,高效率

  • Tomcat配置及如何在Eclipse中启动

    如何安装和配置Tomcat8 Apache Tomcat是目前最常见和流行的基于java的web容器.在本文中,我将向您展示如何安装tomcat8并调整配置文件. Tomcat的主要优点是占地面积小,配置简单,社区参与历史悠久.通常,开发人员可以在5到10分钟(包括tomcat下载时间)内启动并运行一个功能强大的Tomcat安装.Tomcat只需要很少的开箱即用配置就可以在开发机器上运行良好,但是它也可以进行显著的调优,以便在高负载.高可用性的生产环境中运行良好.您可以创建大型Tomcat集群来

  • 如何在IDEA中快速解决Jar冲突详解

    目录 一.为什么会产生Jar包冲突? 1.1 直接与传递依赖 1.2 Maven 的传递依赖 1.3 Maven 如何解决版本冲突? 1.4 覆盖传递依赖版本 1.5 使用直接依赖覆盖传递依赖版本 二.通过IDEA快捷解决依赖冲突 2.1 查找冲突 2.2 发现冲突 2.3 解决冲突 一.为什么会产生Jar包冲突? 作为 Java 开发人员,我们可能会使用 Maven 维护许多应用程序以进行依赖项管理.这些应用程序需要不时升级以保持最新状态并添加新功能或安全更新. 由于某些依赖项之间的冲突,这个

  • 如何在Java中实现一个散列表

    目录 前言: 优化1 优化2 优化3 如何实现 总结 前言: 假设现在有一篇很长的文档,如果希望统计文档中每个单词在文档中出现了多少次,应该怎么做呢? 很简单! 我们可以建一个HashMap,以String类型为Key,Int类型为Value: 遍历文档中的每个单词 word ,找到键值对中key为 word 的项,并对相关的value进行自增操作. 如果该key= word 的项在 HashMap中不存在,我们就插入一个(word,1)的项表示新增. 这样每组键值对表示的就是某个单词对应的数量

  • 如何在AngularJs中调用第三方插件库

    在AngularJs中我们会不可避免的使用第三方库,例如jquery插件库.我们不能散乱的在AngularJS中引入这些库,例如在controller中.那么应该怎么在Angular中使用第三方库呢? 如何使用? 很简单,给插件写一个directive. 在这里,我会使用一个简单的jquery插件Toolbar.js 的DEMO. 这是我们如何在jquery中创建一个tooltip的: <!-- Click this to see a toolbar --> <div id="

随机推荐