引言:
在項目開發中,我們會遇到位元組流與比特流互相轉換、逐位元組、逐位操作的場景。沒有現成的庫供我們調用,需要我們自己實作之。
一、位元組流、位流介紹
【維基百科--位元組流】:在計算機科學裡面,位元組流(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