为什么这段代码的输出是:
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
这可能与二进制补码有关,但我不知道如何。
最佳答案
TLDR:使用 Uvarint
方法正确解码 unsigned 字节 .. 这就是 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
在这一点上,结果不等于 0.. 所以结果是反转的:
11111111
这是 -1
的符号表示(注意符号位现在是 1 .. 表示负数)。
关于Go Varint 返回预期值的一半,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28036560/