如何在 Go 中填写 void* C 指针?
How can I fill out void* C pointer in Go?
我正在尝试与 Go 中的一些 C 代码进行交互。使用 cgo,这一直是相对简单的,直到我遇到这个(相当常见的)案例:需要传递一个指向本身包含指向某些数据的指针的结构的指针。如果不求助于将结构的创建放入 C 代码本身,我似乎无法弄清楚如何从 Go 中做到这一点,我不想这样做。这是一个说明问题的片段:
package main
// typedef struct {
// int size;
// void *data;
// } info;
//
// void test(info *infoPtr) {
// // Do something here...
// }
import "C"
import "unsafe"
func main() {
var data uint8 = 5
info := &C.info{size: C.int(unsafe.Sizeof(data)), data: unsafe.Pointer(&data)}
C.test(info)
}
虽然编译正常,但尝试 运行 结果是:
panic: runtime error: cgo argument has Go pointer to Go pointer
在我的例子中,传递给 C 调用的数据不会在调用后持续存在(即有问题的 C 代码深入结构,复制它需要的内容,然后 returns)。
请参阅 cgo
文档中的 "Passing pointers" 部分:
Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers.
还有:
These rules are checked dynamically at runtime. The checking is controlled by the cgocheck setting of the GODEBUG environment variable. The default setting is GODEBUG=cgocheck=1, which implements reasonably cheap dynamic checks. These checks may be disabled entirely using GODEBUG=cgocheck=0. Complete checking of pointer handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
如果您 运行 您提供的代码段:
GODEBUG=cgocheck=0 go run snippet.go
那就没有恐慌了。但是,正确的方法是使用 C.malloc
(或从其他地方获取 "C pointer"):
package main
// #include <stdlib.h>
// typedef struct {
// int size;
// void *data;
// } info;
//
// void test(info *infoPtr) {
// // Do something here...
// }
import "C"
import "unsafe"
func main() {
var data uint8 = 5
cdata := C.malloc(C.size_t(unsafe.Sizeof(data)))
*(*C.char)(cdata) = C.char(data)
defer C.free(cdata)
info := &C.info{size: C.int(unsafe.Sizeof(data)), data: cdata}
C.test(info)
}
之所以有效,是因为虽然不允许使用常规的 Go 指针,但 C.malloc
returns a "C pointer":
Go pointer means a pointer to memory allocated by Go (such as by using the & operator or calling the predefined new function) and the term C pointer means a pointer to memory allocated by C (such as by a call to C.malloc). Whether a pointer is a Go pointer or a C pointer is a dynamic property determined by how the memory was allocated.
请注意,您需要包含 stdlib.h
才能使用 C.free
。
我正在尝试与 Go 中的一些 C 代码进行交互。使用 cgo,这一直是相对简单的,直到我遇到这个(相当常见的)案例:需要传递一个指向本身包含指向某些数据的指针的结构的指针。如果不求助于将结构的创建放入 C 代码本身,我似乎无法弄清楚如何从 Go 中做到这一点,我不想这样做。这是一个说明问题的片段:
package main
// typedef struct {
// int size;
// void *data;
// } info;
//
// void test(info *infoPtr) {
// // Do something here...
// }
import "C"
import "unsafe"
func main() {
var data uint8 = 5
info := &C.info{size: C.int(unsafe.Sizeof(data)), data: unsafe.Pointer(&data)}
C.test(info)
}
虽然编译正常,但尝试 运行 结果是:
panic: runtime error: cgo argument has Go pointer to Go pointer
在我的例子中,传递给 C 调用的数据不会在调用后持续存在(即有问题的 C 代码深入结构,复制它需要的内容,然后 returns)。
请参阅 cgo
文档中的 "Passing pointers" 部分:
Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers.
还有:
These rules are checked dynamically at runtime. The checking is controlled by the cgocheck setting of the GODEBUG environment variable. The default setting is GODEBUG=cgocheck=1, which implements reasonably cheap dynamic checks. These checks may be disabled entirely using GODEBUG=cgocheck=0. Complete checking of pointer handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
如果您 运行 您提供的代码段:
GODEBUG=cgocheck=0 go run snippet.go
那就没有恐慌了。但是,正确的方法是使用 C.malloc
(或从其他地方获取 "C pointer"):
package main
// #include <stdlib.h>
// typedef struct {
// int size;
// void *data;
// } info;
//
// void test(info *infoPtr) {
// // Do something here...
// }
import "C"
import "unsafe"
func main() {
var data uint8 = 5
cdata := C.malloc(C.size_t(unsafe.Sizeof(data)))
*(*C.char)(cdata) = C.char(data)
defer C.free(cdata)
info := &C.info{size: C.int(unsafe.Sizeof(data)), data: cdata}
C.test(info)
}
之所以有效,是因为虽然不允许使用常规的 Go 指针,但 C.malloc
returns a "C pointer":
Go pointer means a pointer to memory allocated by Go (such as by using the & operator or calling the predefined new function) and the term C pointer means a pointer to memory allocated by C (such as by a call to C.malloc). Whether a pointer is a Go pointer or a C pointer is a dynamic property determined by how the memory was allocated.
请注意,您需要包含 stdlib.h
才能使用 C.free
。