我正在尝试与 Go 中的一些 C 代码交互。使用 cgo,这一直相对简单,直到我遇到这种(相当常见)的情况:需要将指针传递给本身包含指向某些数据的指针的结构。我似乎无法弄清楚如何从 Go 中做到这一点,而不诉诸于将结构的创建放入 C 代码本身中,而我不想这样做。这是说明问题的片段:
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 代码深入结构,复制所需内容,然后返回)。
See 《传递指针》 https://golang.org/cmd/cgo/#hdr-Passing_pointers部分在cgo
docs:
Go 代码可以将 Go 指针传递给 C,前提是它指向的 Go 内存不包含任何 Go 指针。
并且:
这些规则在运行时动态检查。检查由 GODEBUG 环境变量的 cgocheck 设置控制。默认设置是 GODEBUG=cgocheck=1,它实现相当便宜的动态检查。使用 GODEBUG=cgocheck=0 可以完全禁用这些检查。通过 GODEBUG=cgocheck=2 可以对指针处理进行完整的检查,但会花费一些运行时间。
如果您运行您提供的代码片段:
GODEBUG=cgocheck=0 go run snippet.go
然后就没有恐慌了。然而,正确的方法是使用C.malloc
(或者从其他地方获取“C 指针”):
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
返回一个“C 指针”:
Go 指针表示指向由 Go 分配的内存的指针(例如通过使用 & 运算符或调用预定义的 new 函数),术语 C 指针表示指向由 C 分配的内存的指针(例如通过调用 C.malloc)。指针是 Go 指针还是 C 指针是一个动态属性,由内存分配方式决定。
请注意,您需要包括stdlib.h
to use C.free
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)