英文:
golang cast memory to struct
问题
我正在将遗留代码移植到Go语言,这段代码是高性能的,我在翻译程序的一部分时遇到了困难,该部分用于读取共享内存以供后续解析。
在C语言中,我只需将内存强制转换为结构体,然后正常访问即可。
在Go语言中,实现相同结果的最高效和惯用的方法是什么?
英文:
I'm working on porting legacy code to golang, the code is high performance and I'm having trouble translating a part of the program that reads of a shared memory for later parsing.
In c I would just cast the memory into a struct and access it normally.
What is the most efficient and idiomatic to achieve the same result in go?
答案1
得分: 9
如果你想将一个字节数组转换为结构体,可以使用 unsafe 包来实现。这里有一个可行的示例:
在这种方式下,你可以使用的结构体字段类型有一些限制。
切片和字符串除非你的 C 代码产生了与相应切片/字符串头部完全匹配的内存布局,否则是不可行的。
如果只涉及固定大小的数组和 (u)int(8/16/32/64) 等类型,下面的代码可能已经足够了。否则,你将需要手动复制和分配每个结构体字段。
package main
import "fmt"
import "unsafe"
type T struct {
A uint32
B int16
}
var sizeOfT = unsafe.Sizeof(T{})
func main() {
t1 := T{123, -321}
fmt.Printf("%#v\n", t1)
data := (*(*[1<<31 - 1]byte)(unsafe.Pointer(&t1)))[:sizeOfT]
fmt.Printf("%#v\n", data)
t2 := (*(*T)(unsafe.Pointer(&data[0])))
fmt.Printf("%#v\n", t2)
}
请注意,(*[1<<31 - 1]byte)
实际上并不会分配这么大的字节数组。这是一个技巧,用于确保可以通过 ...[:sizeOfT]
部分创建一个正确大小的切片。大小 1<<31 - 1
是 Go 中任何切片可能具有的最大大小。至少在过去是这样的。我不确定现在是否仍然适用。无论如何,你将需要使用这种方法来获取一个正确大小的字节切片。
英文:
If you want to cast an array of bytes to a struct, the unsafe package can do it for you. Here is a working example:
There are limitations to the struct field types you can use in this way.
Slices and strings are out, unless your C code yields exactly the right memory layout for the respective slice/string headers, which is unlikely.
If it's just fixed size arrays and types like (u)int(8/16/32/64), the code below may be good enough. Otherwise you'll have to manually copy and assign each struct field by hand.
package main
import "fmt"
import "unsafe"
type T struct {
A uint32
B int16
}
var sizeOfT = unsafe.Sizeof(T{})
func main() {
t1 := T{123, -321}
fmt.Printf("%#v\n", t1)
data := (*(*[1<<31 - 1]byte)(unsafe.Pointer(&t1)))[:sizeOfT]
fmt.Printf("%#v\n", data)
t2 := (*(*T)(unsafe.Pointer(&data[0])))
fmt.Printf("%#v\n", t2)
}
Note that (*[1<<31 - 1]byte)
does not actually allocate a byte array of this size. It's a trick used to ensure a slice of the correct size can be created through the ...[:sizeOfT]
part. The size 1<<31 - 1
is the largest possible size any slice in Go can have. At least this used to be true in the past. I am unsure of this still applies. Either way, you'll have to use this approach to get a correctly sized slice of bytes.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论