Go Varint返回预期值的一半

时间:2015-01-20 01:55:18

标签: go

为什么输出此代码:

package main

import (
    "fmt"
    "encoding/binary"
)

func main() {
    var myByte byte = 18
    array := []byte{myByte}
    val, n := binary.Varint(array)
    fmt.Printf("value: %d, num bytes: %d\n", val, n)
}

value: 9, num bytes: 1代替value: 18, num bytes: 1

它可能与两个补码有关,但我没有看到如何。

2 个答案:

答案 0 :(得分:1)

TLDR:使用Uvarint方法正确解码无符号字节..默认情况下为byte

字节存储无符号(默认情况下,字节无符号 - 在大多数语言中它是uint8的别名。)

当您解码号码时,您需要拨打binary.Varint ..来解码已签名的号码。由于符号位,这导致数字不正确。

使用binary.Uvarint ..即解码无符号数字,您将得到正确的结果:

val, n := binary.Uvarint(array) // val = 18, n = 1

扩展示例:

让我们来看看你的号码 - 18.二进制,就是这样:

00010010

binary.Varint功能如下:

func Varint(buf []byte) (int64, int) {
    ux, n := Uvarint(buf) // ok to continue in presence of error
    x := int64(ux >> 1)
    if ux&1 != 0 {
        x = ^x
    }
    return x, n
}

基本上,它会首先获得您提供的无符号值:18

然后它将所有字节移过1.这导致:

00001001

这是9的二进制表示。请注意,符号位仍为0 - 表示正数。然后,它检查是否按原样反转结果并使用18原始值(1)。它之所以这样做,是因为它使用的是"我知道这个号码已签名"上下文 - 这就是函数存在的原因:

00010010
00000001
--------
00000000
     = 0

此时,零确实等于零 - 因此方法返回x - 即9。

让我们试试1

使用1作为输入:

00000001

向右移动:

00000000

AND 原始号码(1) 1:

00000001
00000001
--------
     = 1

此时,结果不等于零..所以结果反转:

11111111

这是-1的签名表示(注意符号位现在为1 ..表示负数)。

答案 1 :(得分:0)

是。检查此修改后的版本:http://play.golang.org/p/AyP2a4gue8

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    for i := 0; i < 100; i++ {
        var myByte byte = byte(i)
        array := []byte{myByte}
        val, n := binary.Varint(array)
        fmt.Printf("int %d value: %d, num bytes: %d\n", i, val, n)

    }    
}

产生以下输出:

int 0 value: 0, num bytes: 1
int 1 value: -1, num bytes: 1
int 2 value: 1, num bytes: 1
int 3 value: -2, num bytes: 1
int 4 value: 2, num bytes: 1
int 5 value: -3, num bytes: 1
int 6 value: 3, num bytes: 1
int 7 value: -4, num bytes: 1
int 8 value: 4, num bytes: 1
int 9 value: -5, num bytes: 1
int 10 value: 5, num bytes: 1
int 11 value: -6, num bytes: 1
int 12 value: 6, num bytes: 1
int 13 value: -7, num bytes: 1
int 14 value: 7, num bytes: 1
int 15 value: -8, num bytes: 1
int 16 value: 8, num bytes: 1
int 17 value: -9, num bytes: 1
int 18 value: 9, num bytes: 1

你可以看到否定与正面之间的“锯齿形”。这是因为,根据documented binary format,varints使用“zig-zag”编码,因此小绝对值的值用较小的值编码。