建设公司门户网站,温州网站开发公司,免费建站系统博客,临安区建设局网站前一篇博客 varint原理 - 正数的编码和解码_YZF_Kevin的博客-CSDN博客我们讲了varint的实现原理#xff0c;举例也分析对于正数的编码#xff0c;解码过程 本篇博客#xff0c;我们开始举例分析负数的编码和解码#xff0c;因为负数有原码#xff0c;反码#xff0c;补码…前一篇博客 varint原理 - 正数的编码和解码_YZF_Kevin的博客-CSDN博客我们讲了varint的实现原理举例也分析对于正数的编码解码过程 本篇博客我们开始举例分析负数的编码和解码因为负数有原码反码补码的概念如果大家对这一块不熟可以先看下我的这篇博客里面有详细的解释 大端 小端 原码 反码 补码 及内存中的表现_YZF_Kevin的博客-CSDN博客 先回顾下varint的编码解码过程
编码原理
varint 对数字的二进制从右往左每7位分割成一块
如果不是最后一块则最左边补1组成一个字节
如果是最后一块则左边缺的全部补0组成1个字节
最终保存的时候根据分割块的顺序依次从左往右填
解码原理
读取字节流后从左往右逐个字节判断
如果该字节最左边为1说明varint值没读取完后面的字节还是本varint的值继续读。本字节最左边的1去掉后剩下的7位留作备用
如果该字节最左边为0说明varint值读取完毕
最终根据分割块的顺序依次从右往左填组成的字节流按int型解析即可 举例
数字 -1负数在内存中以补码形式存放先计算补码我们以32位的整型为例
-1的源码10000000 00000000 00000000 00000001符号位为1表负其他跟正数一样
-1的反码11111111 11111111 11111111 11111110 符号位不变其他位全部取反
-1的补码11111111 11111111 11111111 11111111 反码1即可
但是varint对负数统一是用64位来表示的所以
64位的-1在内存中表示如下
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
每7位标一个颜色一共分成了10块64 7 * 9 1
1 1111111 1111111 1111111 1111111 1111111 1111111 1111111 1111111 1111111
编码过程
1. 从右往左依次取7位第一次取出来的1111111因为自己不是最后一块根据规则左边补1得到11111111
2. 重复上面的步骤依次处理每块数据
3. 最后一块1因为是最后一块了根据规则左边补0得到00000001
把这些分割后新组成的块从左往右填
所以最终varint表示法-1的最终格式是
11111111 11111111 11111111 1111111111111111 11111111 1111111 11111111 11111111 00000001
动手实验
proto文件和程序如下注意我们定义的是int32类型
// 玩家信息
message Player {int32 uniNum 1; // 唯一序号
} 实验结果可以看到实际经过Marshal()序列化之后-1确实占用了10个字节内容和我们计算的完全一样 结论
1. varint可以对正数编码也可以对负数编码
2. varint编码用来表示负数时即使指定了int32类型varint一样会作为int64来处理且发送时要占用10个字节非常坑 针对varint这个问题protobuffer也做出了优化可以使用sint32那就是我们下一篇要讲的zigzag编码
protobuf中zigzag编码原理_YZF_Kevin的博客-CSDN博客