如何在Go中填写void * C指针? [英] How can I fill out void* C pointer in Go?

查看:83
本文介绍了如何在Go中填写void * C指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试与Go中的某些C代码进行交互.使用cgo,在我遇到这种(相当普遍的)情况之前,这一直是相对简单的:需要将指针传递给本身包含指向某些数据的指针的结构.我似乎无法从Go中弄清楚如何做到这一点,而不必诉诸将结构的创建放入C代码本身中,而我不希望这样做.这是一个说明问题的代码段:

I am trying to interface with some C code from Go. Using cgo, this has been relatively straight-forward until I hit this (fairly common) case: needing to pass a pointer to a structure that itself contains a pointer to some data. I cannot seem to figure out how to do this from Go without resorting to putting the creation of the structure into the C code itself, which I'd prefer not to do. Here is a snippet that illustrates the problem:

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)
}

虽然可以正常编译,但尝试运行它会导致:

While this compiles fine, trying to run it results in:

panic: runtime error: cgo argument has Go pointer to Go pointer

就我而言,传递给C调用的数据不会在调用之后持续存在(即,所讨论的C代码深入结构,复制所需内容,然后返回).

In my case, the data being passed to the C call doesn't persist past the call (i.e. the C code in question digs into the structure, copies what it needs, then returns).

推荐答案

请参见传递指针" cgo 文档中的部分:

See "Passing pointers" section in cgo docs:

只要Go代码所指向的Go存储器不包含任何Go指针,Go代码就可以将Go指针传递给C.

Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers.

还有:

这些规则在运行时动态检查.该检查由GODEBUG环境变量的cgocheck设置控制.默认设置为GODEBUG = cgocheck = 1,它实现了相当便宜的动态检查.可以使用GODEBUG = cgocheck = 0完全禁用这些检查.可以通过GODEBUG = cgocheck = 2获得对指针处理的完整检查,而这需要花费一些运行时间.

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.

如果运行附带的代码段:

If you run the snippet you've provided with:

GODEBUG=cgocheck=0 go run snippet.go

那么就没有恐慌了.但是,正确的方法是使用 C.malloc (或从其他位置获取"C指针"):

Then there is no panic. However, the correct way to go is to use C.malloc (or obtain a "C pointer" from somewhere else):

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指针":

It works because while regular Go pointers are not allowed, C.malloc returns a "C pointer":

Go指针表示指向由Go分配的内存的指针(例如通过使用&运算符或调用预定义的新函数),术语C指针表示指向由C分配的内存的指针(例如通过对C的调用).malloc).指针是Go指针还是C指针是一个动态属性,由内存分配方式决定.

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 .

Note that you need to include stdlib.h to use C.free.

这篇关于如何在Go中填写void * C指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆