天天看點

位元組流與位流的互相轉換實作

引言:

在項目開發中,我們會遇到位元組流與比特流互相轉換、逐位元組、逐位操作的場景。沒有現成的庫供我們調用,需要我們自己實作之。

一、位元組流、位流介紹

【維基百科--位元組流】:在計算機科學裡面,位元組流(byte stream)是一種位流,不過裡面的比特被打包成一個個我們叫做位元組(Bytes)的機關。

【位元組流範例】:在網絡傳輸協定裡面比較有名,且會提供位元組流給用戶端的範例是TCP/IP通訊協定裡面的傳輸控制協定(TCP),這種協定提供了雙向的位元組流。

【維基百科--位元流】:一個位元流(bitstream或bit stream)是一個位元的序列。一個位元組流則是一個位元組的序列,一般來說一個位元組是8個位元。也可以被視為是一種特殊的位元流。

【位元流範例】:位元流在遠端通信和計算這些領域裡面被廣泛的使用:舉例來說,同步光網絡通信科技會傳輸同步位元流。

在項目的開發中,我們經常會遇到對于給定的字元串“0123456789abcdef”(位元組流,16個位元組),我們需要其轉化為對應的二進制位流(其中0對應的ASCII碼元為0x30,對應二進制為00110000,一個位元組用8個二進制模拟輸出,合計16*8=128個二進制資料)。

沒有現成的庫函數供我們調用,是以考慮位元組流的特點,加上位元算的操作,以下是其互相轉換的完整的實作及測試用例。

二、位元組流轉為位流的核心操作——如何擷取到每一位

方法:通過右移操作,然後與1(0000 0001)求與的方式。

如下表所示,依次實作0x30右移動(1,2,3,4…)位,然後與0000 0001進行與操作;顯然,隻有當移動到的末位為1時兩者與操作才為1(右移動4位),其他都為0。如:

初始 右移0位 >>0 0x30 00110000
右移1位 右移1位 >>1 0x18 00011000
右移2位 右移2位 >>2 0x0c 00001100
右移3位 右移3位 >>3 0x06 00000110
右移4位 右移4位 >>4 0x03 00000011

三、位流轉為位元組流的核心:如何将8位合為一個位元組

比特流 位元組流
0011 0000 0128+064+132+116+0=48(10進制)=0x30(16進制)

方法一:通過傳統每位與基數相乘累計求和的方式實作。

方法二:每8位一個單元,”或”的方式模拟求和(與位元組流轉化為位流方法相反),詳見代碼。

四、位流與位元組流互相轉化的實作

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
using namespace std;
 
#define  UCHAR  unsigned char
const int MULTIPLE = 8;       //位元組流長度是位流的8倍
const int FIX_VAL = 0X01;     //求&專用特定值
const int g_BinArr[MULTIPLE] = {128,64,32,16,8,4,2,1}; //2的次幂
 
/*
**@brief 位元組流轉為位流
**@param [in]puchByte,位元組流;[in]iByteLen,位元組流長度; 
   [in&out]puchBit,位流; [in&out]iBitLen,位流長度
**@return 空
*/
void byte_to_bit(const UCHAR *puchByte, const int& iByteLen, UCHAR *puchBit, int *pBitLen)
{
 assert(puchByte != NULL && iByteLen >0 && puchBit != NULL && pBitLen !=NULL);
 
 int iBitLen = 0;
 for (int i = 0; i < iByteLen; i++)
 {
  for(int j = 0; j < MULTIPLE; j++)
  {
   //printf("%0x >> %d = %0x\n", puchByte[i], j, puchByte[i]>>j);
   puchBit[i*MULTIPLE + MULTIPLE - 1 - j] = ((puchByte[i])>>j)&FIX_VAL;
   iBitLen++;
  }//end for j
 }//end for 
 
 *pBitLen = iBitLen;
}           
/*
**@brief 位流轉為位元組流
**@param [in]puchBit,位流;[in]iBitLen,位流長度; 
   [in&out]puchByte,位元組流 [in&out]pByteLen,位元組流長度
**@return 空
*/
void bit_to_byte(const UCHAR *puchBit, const int& iBitLen, UCHAR *puchByte, int* pByteLen)
{
 assert(puchBit && iBitLen > 0 && puchByte && pByteLen);
 int iByteNo = 0;  
 int iBitInByte = 0;
 for(int i = 0; i < iBitLen; i++)
 {
  iByteNo = i/MULTIPLE;    //位元組序号
  iBitInByte = i%MULTIPLE; //位元組裡的比特序号(0-7)
 
  puchByte[iByteNo] += puchBit[i]*g_BinArr[iBitInByte];  //累計求和
  
  //cout << "iByteNo =:" << iByteNo << "\t iBitInByte = " << iBitInByte \
  //<< "\t puchByte[iByteNo] = " << puchByte[iByteNo] << endl;
 }//end for i
 *pByteLen = iBitLen/MULTIPLE;
}           
/*
**@brief 位流轉為位元組流[方法二]
**@param [in]puchBit,位流;[in]iBitLen,位流長度; 
   [in&out]puchByte,位元組流; [in&out]位元組流長度
**@return 空
*/
void bit_to_byte_ext(const UCHAR *puchBit, const int& iBitLen, UCHAR *puchByte, int* iByteLen)
{
 assert(puchBit && iBitLen > 0 && puchByte && iByteLen);
 
 int iByteNo = 0;              //位元組号
 UCHAR uchTmp = 0; 
 for(int i = 0; i < iBitLen; i+=MULTIPLE)
 {
  for(int j = 0; j < MULTIPLE; j++)
  {
   //通過或的方式累計求和
   uchTmp |= ((puchBit[i + j])<<(MULTIPLE - 1 - j));
  }
  //printf("uchTmp = %0x\n",uchTmp);
  puchByte[iByteNo] = uchTmp;
  
  iByteNo++;    //位元組号+1
  uchTmp = 0;
 }//end for i
 
 *iByteLen = iByteNo;
}           
/*
**@brief 測試位流與位元組流互轉
**@param  空
**@return 空
*/
void test_byte_bit()
{
 const UCHAR uchByte[] = "0123456789abcdef";        //原始位元組流
 int iByteLen = sizeof(uchByte)/sizeof(UCHAR) - 1;  //原始位元組流長度
 int iBitLen = MULTIPLE*iByteLen;                   //比特流長度
 UCHAR *puchBit = new UCHAR[iBitLen];
 memset(puchBit, 0, iBitLen);
 
 cout << "原始位元組流為: ";
 #if 0
 for (int i = 0; i < iByteLen; i++)
 {
  printf("%0x\t", uchByte[i]);                  
 }
 printf("\n");
 #endif
 cout << uchByte << endl;
 
 int iBitLenX = 0;
 byte_to_bit(uchByte, iByteLen, puchBit, &iBitLenX);  //位元組轉化為比特流
 
 cout << "測試位元組流轉化過的位流為: " << endl;
 for (int i = 0; i < iBitLen; i++)
 {
  printf("%0x",puchBit[i]);
 }
 printf("\n");
 cout << "位流長度為: " << iBitLenX << endl << endl;
 
 UCHAR* puchByte = new UCHAR[1 + iByteLen];
 memset(puchByte, 0, 1 + iByteLen);
 int iByteLenX = 0;
 
 #if 1
 bit_to_byte(puchBit, iBitLen, puchByte, &iByteLenX);    //比特流轉化位元組流方法1
 #endif
 
 #if 0
 bit_to_byte_ext(puchBit, iBitLen, puchByte, &iByteLenX); //比特流轉化位元組流方法2
 #endif
 
 cout << "測試位流轉化過的位元組流為: " << endl;
 
 for (i = 0; i < iByteLen; i++)
 {
  printf("%0x\t",puchByte[i]);
 }
 printf("\n");
 
 cout << "位流轉為成的位元組流為: " << puchByte << endl;
 cout << "位元組流的長度為: " << iByteLen << endl;
 
 if (puchBit != NULL)
 {
  delete []puchBit;
  puchBit = NULL;
 }
 if (puchByte != NULL)
 {
  delete []puchByte;
  puchByte = NULL;
 }
}
 
int main()
{
 test_byte_bit();
 
 return 0;
}           

五、結語:

根據代碼走讀,會加深對于位元組流與位流互相轉換的了解。

作者:銘毅天下

轉載請标明出處,原文位址:

http://blog.csdn.net/laoyang360/article/details/17310793

繼續閱讀