将 [32]byte 转换为 [8]uint32。

huangapple go评论102阅读模式
英文:

Convert [32]byte to [8]uint32

问题

我有256位存储在[32]byte中。

我想将其转换为[8]uint32,其中第一个uint32存储前四个字节,依此类推。

我即将编写一个函数来通过将位移动到正确的位置等方式来实现此目的,我想知道在Go中是否有更简单的方法来做到这一点?

英文:

I have 256 bits stored in a [32]byte.

I want to convert this to an [8]uint32, with the first uint32 storing the first four bytes, etc.

I'm about to write a function that does this by shifting the bits into the correct positions etc, I wonder if there is an easier way to do this in Go?

答案1

得分: 10

使用binary.ByteOrder

encoding/binary包使得从字节切片中读取uint32值变得很容易。可以使用binary.ByteOrder接口类型的值来实现。binary.LittleEndian是一个导出的变量,可以直接使用。将以下代码放入一个简单的for循环中以读取所有8个值:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

for i := 0; i < len(data); i += 4 {
    ints[i/4] = binary.LittleEndian.Uint32(data[i:])
}

fmt.Println(ints)

输出结果(在Go Playground上尝试):

[1 2 0 0 0 0 0 0]

当然,这对于任意字节数(是4的倍数)都适用,不仅仅是32。

使用binary.Read()

另一种更简洁的方法是使用binary.Read()

func Read(r io.Reader, order ByteOrder, data interface{}) error

当然,这需要一个io.Reader,可以使用bytes.NewBuffer()来创建。这样,转换只需要一行代码:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

err := binary.Read(bytes.NewBuffer(data[:]), binary.LittleEndian, &ints)

fmt.Println(ints, err)

输出结果(在Go Playground上尝试):

[1 2 0 0 0 0 0 0] <nil>

使用unsafe.Pointer

为了完整起见,这里还有另一种_不安全_的方法。由于数组在内存中是连续排列的,两个数组占用相同的大小。我们可以将输入的内存区域解释为输出类型的值:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

ints = *(*[8]uint32)(unsafe.Pointer(&data))

fmt.Println(ints)

输出结果(在Go Playground上尝试):

[1 2 0 0 0 0 0 0]

这是最高效且最不安全的解决方案。

在这种情况下,像上面展示的方式是安全的,但是请谨慎使用unsafe包,并将其作为最后的手段。许多其他看似非常相似的情况可能无法正常工作。我们这次是“幸运”的,因为我们有数组,并且输入以小端字节顺序给出,但是对于切片和/或不同的字节顺序,情况可能会有所不同。上面介绍的另外两种方法更通用,可以同时适用于切片和数组。

英文:

Using binary.ByteOrder

The encoding/binary package makes it easy, values of the binary.ByteOrder interface type can be used to read uint32 values from byte slices. There is a binary.LittleEndian exported variable which you can use out of the box. Put this in a simple for loop to read all 8 values:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

for i := 0; i &lt; len(data); i += 4 {
	ints[i/4] = binary.LittleEndian.Uint32(data[i:])
}

fmt.Println(ints)

Output (try it on the Go Playground):

[1 2 0 0 0 0 0 0]

And this of course works for any number of bytes (being multiple of 4), not just for 32.

Using binary.Read()

Another, even shorter alternative would be to use binary.Read():

func Read(r io.Reader, order ByteOrder, data interface{}) error

This of course requires an io.Reader, for which you may use bytes.NewBuffer(). This way the conversion is a simple line:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

err := binary.Read(bytes.NewBuffer(data[:]), binary.LittleEndian, &amp;ints)

fmt.Println(ints, err)

Output (try it on the Go Playground):

[1 2 0 0 0 0 0 0] &lt;nil&gt;

Using unsafe.Pointer

For completeness, here's yet another, unsafe way. Since arrays are laid out sequentially in memory, both arrays occupy the same size. We can interpret the memory area of the input as a value of the output type:

data := [32]byte{1, 0, 0, 0, 2}
ints := [8]uint32{}

ints = *(*[8]uint32)((unsafe.Pointer)(&amp;data))

fmt.Println(ints)

Output (try it on the Go Playground):

[1 2 0 0 0 0 0 0]

This is the most efficient and the most unsafe way to solve your task.

In this case it's safe to do it like presented, but use package unsafe with caution and as a last resort. Many other, seemingly very similar cases might not work. We were "lucky" since we had arrays and input was given in little endian byte order, but with slices and / or with different byte order it would be a different story. The above presented 2 other ways are more general and work both with slices and arrays.

答案2

得分: 1

看起来我可以这样做:

data_uint32[0] = binary.LittleEndian.Uint32(data_bytes[0:4])
data_uint32[1] = binary.LittleEndian.Uint32(data_bytes[4:8])
data_uint32[2] = binary.LittleEndian.Uint32(data_bytes[8:12])
data_uint32[3] = binary.LittleEndian.Uint32(data_bytes[12:16])
data_uint32[4] = binary.LittleEndian.Uint32(data_bytes[16:20])
data_uint32[5] = binary.LittleEndian.Uint32(data_bytes[20:24])
data_uint32[6] = binary.LittleEndian.Uint32(data_bytes[24:28])
data_uint32[7] = binary.LittleEndian.Uint32(data_bytes[28:32])

也许还有更简单的方法,但现在这样做就可以了。

英文:

It seems I can do this using something like:

data_uint32[0] = binary.LittleEndian.Uint32(data_bytes[0:4])
data_uint32[1] = binary.LittleEndian.Uint32(data_bytes[4:8])
data_uint32[2] = binary.LittleEndian.Uint32(data_bytes[8:12])
data_uint32[3] = binary.LittleEndian.Uint32(data_bytes[12:16])
data_uint32[4] = binary.LittleEndian.Uint32(data_bytes[16:20])
data_uint32[5] = binary.LittleEndian.Uint32(data_bytes[20:24])
data_uint32[6] = binary.LittleEndian.Uint32(data_bytes[24:28])
data_uint32[7] = binary.LittleEndian.Uint32(data_bytes[28:32])

Perhaps there's an even simpler way, but this will do for now.

huangapple
  • 本文由 发表于 2017年5月7日 17:37:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/43829976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定