在protobuf

时间:2018-02-16 06:27:27

标签: c++ protocol-buffers google-protocol-buffer

在gpb proto2(https://developers.google.com/protocol-buffers/docs/proto#scalar)的标量类型描述中,它说:

  
      
  • INT32

         

    使用可变长度编码。编码负面效率低下   数字 - 如果您的字段可能具有负值,请使用sint32   代替。

  •   
  • SINT32

         

    使用可变长度编码。签名的int值。这些更多   有效地编码负数而不是常规的int32。

  •   

对于正值,sint32是否与int32一样有效?

换句话说,有没有理由使用int32?

如果使用什么语言很重要,我只对C ++感兴趣。

2 个答案:

答案 0 :(得分:3)

https://developers.google.com/protocol-buffers/docs/encoding#signed-integers

有符号变量通过在正值和负值之间交替进行编码。例如,

   value     int32    zigzag    sint32
          (binary)            (binary)
       0  00000000         0  00000000
      -1  11111111         1  00000001
          11111111
          11111111
          11111111
          00001111
       1  00000001         2  00000010
      -2  11111110         3  00000011
          11111111
          11111111
          11111111
          00001111
...
      63  00111111       126  01111110
     -64  11000000       127  01111111
          11111111
          11111111
          11111111
          00001111
      64  01000000       128  10000000
                              00000001
...

平均而言,正数需要再将一位编码为sint而不是int

(展开并运行以下代码片段进行现场演示。)



function encode_varint(number) {
  if (!number) return [0];
  var bytes = [];
  while (number) {
    var byte = number & 0x7F;
    number >>>= 7;
    if (number) byte |= 0x80;
    bytes.push(byte);
  }
  return bytes;
}
function format_bytes(bytes) {
  var output = '';
  for (var i = 0; i < bytes.length; i++) {
    if (i) output += ' ';
    output += bytes[i].toString(2).padStart(8, '0');
  }
  return output;
}
var valueElem = document.getElementById('value');
var int32Elem = document.getElementById('int32');
var sint32Elem = document.getElementById('sint32');
function update() {
  var value = parseInt(valueElem.value);
  var int32 = encode_varint(value);
  var sint32 = encode_varint(value << 1 ^ -(value < 0));
  int32Elem.value = format_bytes(int32);
  sint32Elem.value = format_bytes(sint32);
}
valueElem.addEventListener('change', update);
update();
&#13;
#varint {
  display: grid;
  grid-template-columns: max-content auto;
  grid-row-gap: 1ex;
  grid-column-gap: 1ch;
}
#varint label {
  text-align: right;
}
#varint input {
  font-family: monospace;
}
&#13;
<form id='varint' onsubmit='return false'>
  <label for='value'>value</label>
  <input id='value' type='number' value='0'>
  <label for='int32'>int32</label>
  <input id='int32' type='text' readonly>
  <label for='sint32'>sint32</label>
  <input id='sint32' type='text' readonly>
</form>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

一些正值将小于int32而不是sint32,但最多只有一个字节。

基本上,protobuf使用&#34; base128&#34;对数字进行编码,其中编码值的每个字节具有7位值数据,并且一位作为&#39;结束&#39;标记以查找编码值的结尾。 &#34; INT32&#34;将数字视为32位二进制补码并将其编码为无符号32位数,因此负值将被编码为大正值并始终需要5个字节。 &#34; SINT32&#34;另一方面,编码为奇怪的符号 - 幅度样式编码,符号位转换为最低有效位(为什么他们没有使用普通的2s补码是一个谜 - 将同样紧凑,但更简单到解码/编码)。

结果是单个字节int32可以表示0-127范围内的数字,而单个字节sint32表示范围为-64..63的数字。因此值64..127将需要2个字节作为sint32,并且只需要一个作为int32