





















Protocol Buffers(protobuf)中的 Varint(Variable-length integer) 是一种可变长度的整数编码格式,用于高效压缩小整数的存储空间。其核心规范如下:
目标:用尽可能少的字节表示整数(尤其适合小值)。
原理:
每个字节的最高位(MSB, Most Significant Bit)是 标志位:
1:表示后续还有字节。
0:表示当前是最后一个字节。
每个字节的低 7 位(bits 0-6)存储实际的数值片段,按 小端序(低位在前)组合。
数值 5 的二进制:00000101
→ 直接编码为 0x05(MSB=0,无需后续字节)。
数值 300 的编码过程:
二进制表示:300 = 1 00101100(9位,需 2 字节)。
分割为 7 位一组(小端序):
低 7 位:0101100(0x2C)→ 加上 MSB=1(还有后续字节):10101100(0xAC)。
高 2 位:0000010(0x02)→ 加上 MSB=0(结束):00000010(0x02)。
最终编码:[0xAC, 0x02](字节序列)。
以字节序列 [0xAC, 0x02] 解码为 300 为例:
读取 0xAC(10101100):
MSB=1 → 还有后续字节。
有效数据:0101100(0x2C)。
读取 0x02(00000010):
MSB=0 → 结束。
有效数据:0000010(0x02)。
组合结果:
0x02 << 7 | 0x2C = 0x12C(即 300)。
先通过 ZigZag 编码 将负数映射到无符号域:
0 → 0, -1 → 1, 1 → 2, -2 → 3, ...
公式:(n << 1) ^ (n >> 31)(32位)。
再按 Varint 编码。
直接使用固定 4/8 字节存储(不适用 Varint)。
| 类型 | 最大字节数 | 数值范围 |
|---|---|---|
| Varint32 | 5 字节 | -2^31 到 2^31-1 |
| Varint64 | 10 字节 | -2^63 到 2^63-1 |
def encode_varint(value):
bytes = []
while value > 0x7F:
bytes.append((value & 0x7F) | 0x80)
value >>= 7
bytes.append(value)
return bytes
def decode_varint(buffer):
result = 0
shift = 0
while True:
byte = buffer.read_byte()
result |= (byte & 0x7F) << shift
if not (byte & 0x80):
break
shift += 7
return result
Protobuf 消息长度前缀:
消息头部的长度字段通常用 Varint32 编码。
整数字段压缩:
如 int32、uint32 等字段的存储优化。
网络传输:
减少小整数的带宽占用。
空间效率:小整数(如 1、42)仅需 1 字节。
兼容性:字段编号(Field Number)和枚举值常用 Varint 编码。
流式解析:无需提前知道整数长度。
性能权衡:
Varint 的解码比固定长度整数稍慢(需位操作和循环)。
负数效率:
直接编码负数(如 int32)可能占用 5 字节,建议用 sint32 通过 ZigZag 优化。
Protobuf 的 Varint 编码通过 动态字节长度 和 MSB 标志位 实现了高效的空间压缩,尤其适合小整数和稀疏数据。理解其规范对优化消息大小和解析性能至关重要
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。