- 論壇徽章:
- 0
|
在TC中,很多地方為了節(jié)約存儲(chǔ)空間,在保存變量時(shí)不會(huì)直接存放變量類型長(zhǎng)度的值(比如4字節(jié)或8字節(jié)的值)到文件中,它會(huì)探測(cè)變量用來(lái)表示值的有效字節(jié)數(shù),然后把這些有意義的字節(jié)保存起來(lái),在后面讀取該變量時(shí),TC會(huì)把該變量的所有有效字節(jié)都讀出來(lái),從而計(jì)算出該變量所表示的值。
為了實(shí)現(xiàn)這個(gè)功能,TC的做法是:把變量的每個(gè)字節(jié)當(dāng)成一個(gè)有符號(hào)數(shù),最高位僅做為符號(hào)位使用,前面7位才用來(lái)表示真正的值,這樣一來(lái),文件中的4個(gè)字節(jié)的數(shù)僅有28位用來(lái)保存長(zhǎng)度信息,如果我們要保存0xFFFFFFFF這個(gè)值,就需要在文件中占用5個(gè)字節(jié),然而,這種情況的值畢竟是少數(shù)(4字節(jié)整型數(shù)只有超過(guò)2^28時(shí)才會(huì)在文件中占用5字節(jié),其它情況都會(huì)少于或等于4字節(jié)),我們一般存放的值都很小,就只需要少于4個(gè)字節(jié)的存儲(chǔ)長(zhǎng)度,比如存放小于2^7的所有值只需要1個(gè)字節(jié)空間,存放2^7到2^14之間的值僅需要2字節(jié)等等,通過(guò)這中方式節(jié)省的空間會(huì)遠(yuǎn)遠(yuǎn)少于我們浪費(fèi)的空間,因此這種做法在節(jié)省文件空間方面還是很有效的。
上面大概講了原理,下面我們來(lái)看看TC中的代碼,看看TC具體怎么實(shí)現(xiàn)的,我會(huì)在下面的代碼中給出注釋說(shuō)明。TC主要通過(guò)2個(gè)宏來(lái)分別完成存放和讀取變長(zhǎng)變量,這2個(gè)宏又分別對(duì)應(yīng)32位版本(最多存取4字節(jié)的值)和64位的版本(最多存放8字節(jié)的值),我僅分析32位的情況,64位情況類似。
1、 把一個(gè)變量按變長(zhǎng)方式放到buffer中
/* set a buffer for a variable length number */
#define TCSETVNUMBUF(TC_len, TC_buf, TC_num) / // TC_num為正整數(shù)
do { /
int _TC_num = (TC_num); /
if(_TC_num == 0){ / // 存放的變量為0
((signed char *)(TC_buf))[0] = 0; /
(TC_len) = 1; / // 返回存放了1個(gè)字節(jié)長(zhǎng)度
} else { /
(TC_len) = 0; /
while(_TC_num > 0){ / // 變量大于0,就一直循環(huán)存放
int _TC_rem = _TC_num & 0x7f; / // 取變量低7位存放
_TC_num >>= 7; / // 變量右移7位
if(_TC_num > 0){ / // 去掉低7位后變量是否還有值?
// 按負(fù)數(shù)存放取得的變量低7位值,減一確保為負(fù)數(shù),因?yàn)橹虚g可能有0
((signed char *)(TC_buf))[(TC_len)] = -_TC_rem - 1; /
} else { / // 保留最后7位,按正數(shù)的形式
((signed char *)(TC_buf))[(TC_len)] = _TC_rem; /
} /
(TC_len)++; / // 存放的長(zhǎng)度加1,表示用了多少字節(jié)來(lái)存放變量
} /
} /
} while(false)
2、 從buffer中讀出按變長(zhǎng)方式存放的變量值
/* read a variable length buffer */
#define TCREADVNUMBUF(TC_buf, TC_num, TC_step) /
do { /
TC_num = 0; /
int _TC_base = 1; /
int _TC_i = 0; / // 從buffer第一個(gè)成員開(kāi)始讀取
while(true){ /
if(((signed char *)(TC_buf))[_TC_i] >= 0){ / // 該字節(jié)大于0,則是最后字節(jié)
TC_num += ((signed char *)(TC_buf))[_TC_i] * _TC_base; / // 累加
break; / // 退出結(jié)束
} /
// 該字節(jié)小于0,則不是最后字節(jié)
TC_num += _TC_base * (((signed char *)(TC_buf))[_TC_i] + 1) * -1; / //累加
_TC_base <<= 7; /
_TC_i++; / // 移動(dòng)buffer
} /
(TC_step) = _TC_i + 1; / // 讀取長(zhǎng)度加1,表示讀了多少字節(jié)的變量
} while(false)
以上為原文,有一點(diǎn)不明白,為什么不把變量的每個(gè)字節(jié)當(dāng)成無(wú)符號(hào)來(lái)存取,這樣不是更減少空間嗎? |
|