英文:
Golang: unsafe dynamic byte array
问题
我正在尝试使用Go语言与Windows的dll进行接口交互。我想要使用的dll函数接受一个指向字节数组的指针,因此我需要提供这个字节数组。
我正在使用syscall库来调用dll,可以在这里看到示例。我的基本要求是:
- 我已经知道了字节数组的所需大小
- 我创建了字节数组
- 我需要获取字节数组的指针
- 然后将指针传递给Windows的dll
我无法弄清楚如何在Go语言中创建字节数组并获取其指针。这显然是一项不安全的操作,unsafe库可能会有所帮助,但首先我需要创建一个动态长度的字节数组。使用"make"创建切片对我没有帮助,除非我能够获取切片的底层数组的指针。
是否有其他人遇到过这个问题或者有任何想法?
英文:
I am trying to interface with a Windows dll using Go. The dll function I want to use accepts a pointer to a byte array. Therefore I need to give it that byte array.
I am using the syscall libary to call the dll, as demonstrated here. My basic requirements are:
- I am given the required size for the byte array
- I create the byte array
- I must get a pointer to the byte array
- I then pass the pointer to the Windows dll
I can't figure out how to create a byte array in go, and get a pointer to it. This is obviously an unsafe operation, and the unsafe library can be helpful, but I need to create a dynamic-length byte array in the first place. Creating a slice with "make" doesn't help me, unless I can get a pointer to the slice's backing array.
Has anyone else encountered this or have any ideas?
答案1
得分: 3
我找到了一个粗略的解决方案。显然,一个切片的结构包含一个指向后备字节数组的指针,后备字节数组的长度,以及后备字节数组的容量。
我只对字节数组的指针感兴趣,所以我只需要切片内部数据的第一个成员。
Go的unsafe.Pointer
无法将切片转换为不安全指针,但它可以将指针转换为切片作为不安全指针。由于我可以将不安全指针转换为任何类型的指针,我可以将其转换为指向指针的指针,从而恢复切片内部数据的第一个成员。
这是一个可行的示例。我想要一个uintptr
,但你可以将其转换为任何指针类型。
package main
import (
"fmt"
"unsafe"
)
func main() {
// 任意大小
n := 4
// 创建一个正确大小的切片
m := make([]int, n)
// 使用复杂的间接方式将切片的前几个字节转换为不安全的uintptr
mPtr := *(*uintptr)(unsafe.Pointer(&m))
// 检查是否成功
m[0] = 987
// (我们必须将uintptr重新转换为*int才能检查它)
fmt.Println(m[0], *(*int)(unsafe.Pointer(mPtr)))
}
如果你想要一个*int
,你可以这样做:mPtr := *(**int)(unsafe.Pointer(&m))
只要切片保持这种内部数据结构,这个方法就有效。我当然愿意接受一个更健壮的解决方案,不依赖于Go内部的结构。
英文:
Well I found one gross solution. Apparently the structure of a slice contains a pointer to the backing byte array, the length of the backing byte array, and then the capacity of the backing byte array.
I am only interested in a pointer to the byte array, so I only need the first member of the slice's internal data.
Go's unsafe.Pointer
will not cast a slice to an unsafe pointer, but it will cast a pointer to a slice as an unsafe pointer. Since I can cast an unsafe pointer to any old type of pointer I want, I can cast it to a pointer-to-a-pointer, which recovers the first member of the slice's internal data.
Here's a working example. I wanted a uintptr
but you could cast it to any pointer type.
package main
import (
"fmt"
"unsafe"
)
func main() {
// Arbitrary size
n := 4
// Create a slice of the correct size
m := make([]int, n)
// Use convoluted indirection to cast the first few bytes of the slice
// to an unsafe uintptr
mPtr := *(*uintptr)(unsafe.Pointer(&m))
// Check it worked
m[0] = 987
// (we have to recast the uintptr to a *int to examine it)
fmt.Println(m[0], *(*int)(unsafe.Pointer(mPtr)))
}
If you wanted a *int
instead, you could do mPtr := *(**int)(unsafe.Pointer(&m))
This works as long as a slice maintains this internal data structure. I am definitely open to a more robust solution that doesn't depend on the structure of Go's internals.
答案2
得分: 3
我认为syscall.ComputerName的实现https://golang.org/src/syscall/syscall_windows.go#395是一个很好的例子。它使用uint16而不是字节,但其他方面...
在你的情况下,应该是ptr := &myslice[0]
。
Alex
英文:
I think syscall.ComputerName implementation https://golang.org/src/syscall/syscall_windows.go#395 would be a good example. It uses uint16s, not bytes, but otherwise ...
In your case it would be ptr := &myslice[0]
.
Alex
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论