16

全部。我遇到了一个似乎很奇怪的问题。(可能是我应该睡着的时间已经过去了,我忽略了一些明显的东西。)

由于一些十六进制解码,我有一个[]byte长度为 8 的结果。我需要制作一个uint64才能使用它。我曾尝试使用binary.Uvarint(), fromencoding/binary这样做,但它似乎只使用数组中的第一个字节。考虑以下示例。

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    num, _ := binary.Uvarint(array[0:8])
    fmt.Printf("%v, %x\n", array, num)
}

它在 play.golang.org 上。

当它运行时,它显示num0,即使在十六进制中,它应该是000108000801ab01。此外,如果从 中捕获第二个值binary.Uvarint(),则它是从缓冲区读取的字节数,据我所知,它应该是 8,即使它实际上是 1。

我解释错了吗?如果是这样,我应该改用什么?

谢谢大家。:)

4

3 回答 3

19

您正在使用一个函数进行解码,该函数的用途不是您需要的:

Varints 是一种使用一个或多个字节对整数进行编码的方法;绝对值较小的数字占用较少的字节数。有关规范,请参阅 http://code.google.com/apis/protocolbuffers/docs/encoding.html

它不是标准编码,而是一种非常具体的可变字节数编码。这就是为什么它在值小于 0x080 的第一个字节处停止。

正如斯蒂芬所指出的, binary.BigEndian 和 binary.LittleEndian 提供了有用的函数来直接解码:

type ByteOrder interface {
    Uint16([]byte) uint16
    Uint32([]byte) uint32
    Uint64([]byte) uint64
    PutUint16([]byte, uint16)
    PutUint32([]byte, uint32)
    PutUint64([]byte, uint64)
    String() string
}

所以你可以使用

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    num := binary.LittleEndian.Uint64(array)
    fmt.Printf("%v, %x", array, num)
}

或者(如果你想检查错误而不是恐慌,感谢 jimt 用直接解决方案指出这个问题):

package main

import (
    "encoding/binary"
    "bytes"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    var num uint64
    err := binary.Read(bytes.NewBuffer(array[:]), binary.LittleEndian, &num)
    fmt.Printf("%v, %x", array, num)
}
于 2012-12-01T08:45:57.800 回答
2

如果不关心字节顺序,你可以试试这个:

arr := [8]byte{1,2,3,4,5,6,7,8}
num := *(*uint64)(unsafe.Pointer(&arr[0]))

http://play.golang.org/p/aM2r40ANQC

于 2016-04-14T04:10:21.223 回答
1

如果您查看Uvarint的函数,您会发现它不像您期望的那样直接转换。

老实说,我还没有弄清楚它期望什么样的字节格式(见编辑)。

但是编写自己的代码几乎是微不足道的:

func Uvarint(buf []byte) (x uint64) {
    for i, b := range buf {
        x = x << 8 + uint64(b)
        if i == 7 {
            return
        }
    }
    return
}

编辑

我不熟悉字节格式。它是一种可变宽度编码,其中每个字节的最高位是一个标志。
如果设置为 0,则该字节是序列中的最后一个。
如果设置为 1,则编码应继续下一个字节。

只有每个字节的低 7 位用于构建 uint64 值。第一个字节将设置 uint64 的最低 7 位,接下来的字节位 8-15 等。

于 2012-12-01T08:38:28.200 回答