Go Varint返回预期值的一半

Go Varint返回预期值的一半,go,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而不是

为什么此代码的输出是:

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的补码有关,但我不知道怎么做。

是的。检查此修改版本:


你可以看到消极和积极之间的“之字形”。这是因为,根据,变量使用“之字形”编码,因此小绝对值的值用小值编码。

TLDR:使用
Uvarint
方法正确解码无符号字节。。这就是默认情况下的
字节

该字节是无符号存储的(因为默认情况下字节是无符号的-在大多数语言中,它是
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
原始编号(1)加上1:

此时,结果不等于零。。结果是相反的:

11111111

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

好的,那么为什么2产生1,1产生-1?好的,但是为什么我输入的18产生9?18 = 00010010
00000000
00000001
00000001
--------
     = 1
11111111