将[8]字节转换为uint64

时间:2012-12-01 07:02:32

标签: go

所有。我遇到了一个似乎很奇怪的问题。 (可能是我睡着了很久了,而且我忽视了一些显而易见的事情。)

由于某些十六进制解码,我有一个长度为8的[]byte。我需要生成一个uint64才能使用它。我尝试使用来自encoding/binary的{​​{3}}来执行此操作,但它似乎只使用数组中的第一个字节。请考虑以下示例。

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)
}

binary.Uvarint()

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

我是否解释了这个错误?如果是这样,我应该使用什么呢?

谢谢,大家好。 :)

3 个答案:

答案 0 :(得分:15)

您正在使用一种功能进行解码,该功能的使用不是您需要的功能:

  

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

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

正如Stephen指出的那样,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)
}

答案 1 :(得分: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等

答案 2 :(得分:1)

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

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

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