golang cast memory to struct

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

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 &quot;fmt&quot;
import &quot;unsafe&quot;

type T struct {
	A uint32
	B int16
}

var sizeOfT = unsafe.Sizeof(T{})

func main() {
	t1 := T{123, -321}
	fmt.Printf(&quot;%#v\n&quot;, t1)

	data := (*(*[1&lt;&lt;31 - 1]byte)(unsafe.Pointer(&amp;t1)))[:sizeOfT]
	fmt.Printf(&quot;%#v\n&quot;, data)

	t2 := (*(*T)(unsafe.Pointer(&amp;data[0])))
	fmt.Printf(&quot;%#v\n&quot;, t2)
}

Note that (*[1&lt;&lt;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&lt;&lt;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.

huangapple
  • 本文由 发表于 2015年2月17日 05:56:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/28551043.html
匿名

发表评论

匿名网友

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

确定