日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Varint

發(fā)布時(shí)間:2023/12/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Varint 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是Varint
Varint 是一種緊湊的表示數(shù)字的方法。它用一個(gè)或多個(gè)字節(jié)來(lái)表示一個(gè)數(shù)字,值越小的數(shù)字使用越少的字節(jié)數(shù)。這能減少用來(lái)表示數(shù)字的字節(jié)數(shù)。

比如對(duì)于 int32 類型的數(shù)字,一般需要 4 個(gè) byte 來(lái)表示。但是采用 Varint,對(duì)于很小的 int32 類型的數(shù)字,則可以用 1 個(gè) byte 來(lái)表示。當(dāng)然凡事都有好的也有不好的一面,采用 Varint 表示法,大的數(shù)字則需要 5 個(gè) byte 來(lái)表示。從統(tǒng)計(jì)的角度來(lái)說(shuō),一般不會(huì)所有的消息中的數(shù)字都是大數(shù),因此大多數(shù)情況下,采用 Varint 后,可以用更少的字節(jié)數(shù)來(lái)表示數(shù)字信息。下面就詳細(xì)介紹一下 Varint。

Varint 中的每個(gè) byte 的最高位 bit 有特殊的含義,如果該位為 1,表示后續(xù)的 byte 也是該數(shù)字的一部分,如果該位為 0,則結(jié)束。其他的 7 個(gè) bit 都用來(lái)表示數(shù)字。因此小于 128 的數(shù)字都可以用一個(gè) byte 表示。大于 128 的數(shù)字,比如 300,會(huì)用兩個(gè)字節(jié)來(lái)表示:1010 1100 0000 0010

下圖演示了 Google Protocol Buffer 如何解析兩個(gè) bytes。注意到最終計(jì)算前將兩個(gè) byte 的位置相互交換過(guò)一次,這是因?yàn)?Google Protocol Buffer 字節(jié)序采用 little-endian 的方式。

從描述上看,Varint與Utf-8編碼有些類似,是變長(zhǎng)編碼。

Varint的實(shí)現(xiàn)分析
看懂上面的例子應(yīng)該不難,下面來(lái)看看LevelDB中是如何實(shí)現(xiàn)的,位置是util\coding.cc

// 計(jì)算編碼后的長(zhǎng)度是幾個(gè)字節(jié)
int VarintLength(uint64_t v) {
? int len = 1;
? while (v >= 128) {
? ? v >>= 7;
? ? len++;
? }
? return len;
}

// 將一個(gè)32位無(wú)符號(hào)int進(jìn)行編碼保存到dst指向的空間
char* EncodeVarint32(char* dst, uint32_t v) {
? // Operate on characters as unsigneds
? unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
? static const int B = 128;
? if (v < (1<<7)) {
? ? *(ptr++) = v;?
? } else if (v < (1<<14)) {
? ? *(ptr++) = v | B;?
? ? *(ptr++) = v>>7;?
? } else if (v < (1<<21)) {
? ? *(ptr++) = v | B;
? ? *(ptr++) = (v>>7) | B;
? ? *(ptr++) = v>>14;
? } else if (v < (1<<28)) {
? ? *(ptr++) = v | B;
? ? *(ptr++) = (v>>7) | B;
? ? *(ptr++) = (v>>14) | B;
? ? *(ptr++) = v>>21;
? } else {
? ? *(ptr++) = v | B;
? ? *(ptr++) = (v>>7) | B;
? ? *(ptr++) = (v>>14) | B;
? ? *(ptr++) = (v>>21) | B;
? ? *(ptr++) = v>>28;
? }
? return reinterpret_cast<char*>(ptr);
}

沒(méi)看源碼時(shí)自己寫(xiě)的代碼是一個(gè)循環(huán),看了源碼才發(fā)現(xiàn)自己還是too young too simple, naive

分析這個(gè)分支發(fā)生了什么:

if (v < (1<<14)) {
? ? *(ptr++) = v | B;?
? ? *(ptr++) = v>>7;?
}
其中v是uint32_t, B是int 值為128, ptr是一個(gè)指向unsiged char類型的指針變量。?
if是判斷v是否需要兩個(gè)字節(jié)表示。如果是就進(jìn)入該分支進(jìn)行處理。?
首先要清楚,如果一個(gè)表達(dá)式中既有無(wú)符號(hào)數(shù)又有int時(shí)(有符號(hào)數(shù)), 那么int值將會(huì)轉(zhuǎn)換為無(wú)符號(hào)數(shù)。(見(jiàn)C++ Primer 第五版 P34)?
那么對(duì)于v | B, B將轉(zhuǎn)換成uint32_t, 那么 v | B 就等價(jià)于:?
v | 00000000 00000000 00000000 10000000?
結(jié)果記為m , m就是將v的第8位置1后的值。(因?yàn)榭隙〞?huì)有后續(xù)字節(jié),所以第八位肯定是1.)?
然后計(jì)算*(ptr++) = v | B, 即 *(ptr++) = m。?
由于*ptr為unsigned char類型,而m為uint32_t, 這時(shí)會(huì)發(fā)生截?cái)唷?ptr即為m的最后8位。

原文鏈接:https://blog.csdn.net/huntinux/article/details/51690665

總結(jié)

以上是生活随笔為你收集整理的Varint的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。