Go语言 将[8]字节转换为uint64

mum43rcc  于 2023-11-14  发布在  Go
关注(0)|答案(3)|浏览(177)

我遇到了一个似乎很奇怪的问题。(可能是我早就应该睡觉了,我忽略了一些明显的东西。)
我有一个长度为8的[]byte作为一些十六进制解码的结果。为了使用它,我需要产生一个uint64。我已经尝试使用binary.Uvarint(),从encoding/binary这样做,但它似乎只使用数组中的第一个字节。考虑下面的例子。

  1. package main
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. )
  6. func main() {
  7. array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
  8. num, _ := binary.Uvarint(array[0:8])
  9. fmt.Printf("%v, %x\n", array, num)
  10. }

字符串

Here it is on play.golang.org.

当它运行时,它将num显示为0,即使在十六进制中,它应该是000108000801ab01。此外,如果从binary.Uvarint()中捕获第二个值,则它是从缓冲区读取的字节数,据我所知,应该是8,即使它实际上是1。
我理解错了吗?如果是的话,我应该用什么来代替?
谢谢大家:)

qc6wkl3g

qc6wkl3g1#

你正在使用一个函数进行解码,而这个函数的用途不是你需要的:
变量类型是一种使用一个或多个字节对整数进行编码的方法;具有较小绝对值的数字占用较少的字节数。有关规范,请参见http://code.google.com/apis/protocolbuffers/docs/encoding.html
这不是标准编码,而是一种非常特殊的可变字节数编码,这就是为什么它在第一个值小于0x 080的字节处停止。
正如Stephen所指出的,binary.BigEndian和binary.LittleEndian提供了有用的函数来直接解码:

  1. type ByteOrder interface {
  2. Uint16([]byte) uint16
  3. Uint32([]byte) uint32
  4. Uint64([]byte) uint64
  5. PutUint16([]byte, uint16)
  6. PutUint32([]byte, uint32)
  7. PutUint64([]byte, uint64)
  8. String() string
  9. }

字符串
所以你可以用

  1. package main
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. )
  6. func main() {
  7. array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
  8. num := binary.LittleEndian.Uint64(array)
  9. fmt.Printf("%v, %x", array, num)
  10. }


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

  1. package main
  2. import (
  3. "encoding/binary"
  4. "bytes"
  5. "fmt"
  6. )
  7. func main() {
  8. array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
  9. var num uint64
  10. err := binary.Read(bytes.NewBuffer(array[:]), binary.LittleEndian, &num)
  11. fmt.Printf("%v, %x", array, num)
  12. }

展开查看全部
oipij1gg

oipij1gg2#

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

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

字符串
http://play.golang.org/p/aM2r40ANQC

xdnvmnnf

xdnvmnnf3#

如果你看一下Uvarint的函数,你会发现它并不像你期望的那样是一个直接的转换。
老实说,我还没有弄清楚它需要什么样的字节格式(参见编辑)。
但是写你自己的几乎是微不足道的:

  1. func Uvarint(buf []byte) (x uint64) {
  2. for i, b := range buf {
  3. x = x << 8 + uint64(b)
  4. if i == 7 {
  5. return
  6. }
  7. }
  8. return
  9. }

字符串

编辑

字节格式是我不熟悉的。它是一种可变宽度编码,每个字节的最高位是一个标志。
如果设置为0,则该字节是序列中的最后一个。
如果设置为1,则编码应继续下一个字节。
只有每个字节的低7位用于构建uint 64值。第一个字节将设置uint 64的低7位,随后的字节位8-15等。

展开查看全部

相关问题