英文:
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 < 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, &ints)
fmt.Println(ints, err)
Output (try it on the Go Playground):
[1 2 0 0 0 0 0 0] <nil>
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)(&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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论