讀功能:將需要儲存的編碼(v)儲存到結構體中(壓縮的最後一步)
寫功能:根據儲存到結構體的壓縮流,讀取 所需要的位大小 的編碼(解壓的第一步。)
(流是個抽象的概念,是對輸入輸出裝置的抽象:
先按壓縮格式,獲得32位每個值對應的壓縮編碼。
每次以32位讀取要壓縮的檔案,並將其轉化成其對應的壓縮編碼並儲存到變數:u32 v 中。
通過位流讀寫器的put_bits()函式 ,將生成的編碼儲存到其中的結構體中。
之後可以寫入檔案,得到壓縮檔案。
如果想將這一段壓縮流解壓,或者讀取壓縮檔案獲得壓縮流
通過位流讀寫器的 get_bits()函式 ,從結構體中獲得想要的位數大小的編碼
之後將其與編碼格式匹配,再轉化,再寫入檔案,完成解壓。
通過統計和計算,得到壓縮編碼(例如):
針對佔4位的值:
符號 值 (十進位制) 值(二進位制) 壓縮編碼 位數
a 0 0000 0 1
b 2 0010 10 2
c 6 0110 110 3
d 7 1110 1110 3
(紅字是位流讀寫器的功能)要完成的操作:將內容為"abacaadb"的檔案(不是字串,而是根據每4位二進位制值不同隨便命名得符號,比寫二進位制方便)讀取並轉化為壓縮流:0 10 0 110 0 0 111 10 (空格只是為了便於檢視),
其中每轉化一次(比如將a(0000)轉化成0後,),都呼叫put_bits(bit_t* s, u32 v, s32 n
)來儲存0到結構體中,且這一次v=0,n=1。
以下**完全來自老師。
其中u32為unsigned 32;
typedef struct bit_t
bit_t;
注意這個結構體不是鍊錶。
1. u32 val; // 當前讀寫器的值
s32 bit; // 當前讀寫器的位數
把每次寫操作抽象成新增到乙個32位讀寫容器中,這個容器的bit只要在寫完後》16位,就將前16位寫入陣列u32 strm[128*1024];
如何寫入呢?見**2.d
注意位流讀寫器32位,從左向右寫入。(這是為了下面操作方便而做的規定)
2.u32 strm[128*1024];為宣告空間的陣列。而寫入或者讀取則通過ptr指標來完成。詳情見下文:**2.d
注意編碼的寫入是通過操做指標ptr寫入的
1:為什麼每次以32位讀取呢?
對於讀取,每次處理的位數越大,速度越快。(一次讀取並處理32位,要比讀4次讀8位快)
而現在的計算機很多32位的,64位的也能相容32位的。
2:u8* ptr;代表?
因為記憶體的基本單位為1位元組即8位,所以用u8來宣告。
通過讓指標指向strm陣列 儲存資料的結束位置,方便以後來完成對資料的寫入,所以ptr-strm就是整個流的位數,
1.進行讀取時,初始化資料結構操作
a.s->ptr = (u8*)s->strm; ptr指標指向陣列的開始位置,因為為空陣列,也是儲存元素的結束位置。
void begin_put_bits(bit_t* s)
2.將已經讀取的編碼v儲存到結構體 *s中
a:為什麼形參中結構體是指標:(bit_t* s, )
b:為什麼v需要左右移動?(v = v << (32 - n) >> s->bit;)
v為32位大小的編碼,但是有效位數為n位。而其他位不一定是0(老師這麼講的,可能和浮點數表示或者轉化編碼時的操作有關,以防萬一吧),所以先左移(32-n)為到最左邊,讓其他位為0。然後需要將其加入當前讀寫容器中。當前讀寫容器的位數為s->bit,要將編碼加在後面,所以需要右移s->bit,編碼位置調整好。然後s->val與v進行或運算,完成新增。
c:為什麼當前讀寫容器的位數大於16位時需要右移16位,然後再將其儲存到陣列strm中?(if (new_bit < 16))
首先:要儲存的內容必須是儲存基本單位8位 的整數倍大小。
其次:編碼v的位數為0到16位;(原因見**3.a),而 s->val的位數為32位,如果s->bit>16位時,不進行左移,那麼再加上編碼v的位數,會超過32位,賦值給s->val時會出現溢位。
d:*((u16*)s->ptr) = s->val >> 16;的講解:
一層一層的分析:*p = x表示將x的值賦給指標p指向的記憶體單元,即將 s->val >> 16的內容賦值給(u16*)s->ptr所指向的記憶體單元。而(u16*)s->ptr則是將s->ptr(指向8位型別的指標)強制型別轉化為(指向16位型別的指標),即s->ptr所指向的空間向下擴大為16位。(注意不是指標變數自己大小的變化)。
上面說了當前位流讀寫器寫入是從左到右,而在計算機中,左邊代表高位,右邊表示低位。
因此 s->val >> 16表示將左邊的16位放到右邊的低位中,因為 s->val為32位,而(u16*)s->ptr指向的位16位記憶體空間,只會寫入低16位。
二級指標又叫雙指標。c語言中不存在引用,所以當你試圖改變乙個指標的值的時候必須使用二級指標。
c++中可以使用引用型別來實現。
寫入之後的操作很明白了:
ptr+2,即位址+2,移到新的位址空間,指向乙個編碼的空間。
再進行s->val <<= 16;左移16位的操作。繼續進行位流讀寫器從左到右寫入的動作。
(注意移位操作不會改變原運算元)
**為:
static inline void put_bit(bit_t* s, u32 v, s32 n) // v: 編碼, n: 編碼的位寬
*((u16*)s->ptr) = s->val >> 16;
s->ptr += 2;
s->val <<= 16;
s->bit = new_bit - 16;
}3.結合上面的每次大於16位左移,這裡要求在呼叫上面函式時32位v的編碼要<=16位。
static inline void put_bits(bit_t* s, u32 v, s32 n)
put_bit(s, v >> 16, n - 16);
put_bit(s, v, 16);
}void end_put_bits(bit_t* s, u8** buf, s32* size)
而對於讀操作,則和寫操作類似,不再敘述
**如下:
void begin_get_bits(bit_t* s, u8* buf, s32 size)
static inline u32 get_bit(bit_t* s, s32 n)
ret = s->val << (32 - s->bit) >> (32 - n);
s->bit -= n;
return ret;
}static inline u32 get_bits(bit_t* s, s32 n)
之前已經寫過huffman壓縮的演算法。可我直接把編碼轉化為了char字元,效率十分低下。
c語言也太靈活了。怕了。
Android MIFARE讀寫器詳解3
射頻識別系統中由於卡片和讀寫器並不是固定連線為乙個不可分割的整體,二者在進行資料通訊前如何確信對方的合法身份就變得非常重要。根據安全級別的要求不同,有的系統不需認證對方的身份,例如大多數的ttf模式的卡片 有的系統只需要卡片認證讀寫器的身份或者讀寫器認證卡片的身份,稱為單向認證 還有的系統不僅卡片要...
中功率高頻讀寫器
產品概述 高頻中功率讀寫器具有極高的讀寫靈敏度和高速多標籤防碰撞能力,讀取標籤速度可達50張 秒,支援iso15693 iso18000 3m1協議標準。應用場景 檔案管理 生產自動化 智慧型餐飲 藥品追蹤 圖書館等領域。產品特性 工作頻率 13.56mhz 射頻功率 1.5w 功率可調 支援協議 ...
串列埠讀寫器C 原始碼
using system using system.drawing using system.collections using system.componentmodel using system.windows.forms using system.data using system.runti...