使用 cgo 将函数指针传递给 C 代码
在 Go v1.6 之前,cgo 允许将 Go 指针传递给 C 代码。然而,在 v1.6 中实现更改后,传递指针的规则发生了显着变化。此更改使得之前从 C 代码调用动态 Go 回调的方法无效。
问题描述
代码示例,曾经是调用 Go 回调的功能示例来自 C,现在会导致运行时错误:
panic: runtime error: cgo argument has Go pointer to Go pointer
解决方案
在新的 cgo 规则下,Go 代码可以仅在以下情况下将 Go 指针传递给 C:它指向的Go内存不包含任何Go指针。如果指向的内存存储 Go 函数/方法指针,此限制会阻止将指针传递给 C 代码。
要克服此限制,可以考虑多种方法。常见的解决方案涉及存储同步数据结构,该数据结构在特定 ID 和实际指针之间建立对应关系。通过将 ID 传递给 C 代码而不是指针,可以绕过限制。
展示此解决方案的更新代码示例:
<code class="go">package gocallback import ( "fmt" "sync" ) /* extern void go_callback_int(int foo, int p1); */ import "C" var mu sync.Mutex var index int var fns = make(map[int]func(C.int)) func register(fn func(C.int)) int { mu.Lock() defer mu.Unlock() index++ for fns[index] != nil { index++ } fns[index] = fn return index } func lookup(i int) func(C.int) { mu.Lock() defer mu.Unlock() return fns[i] } func unregister(i int) { mu.Lock() defer mu.Unlock() delete(fns, i) } //export go_callback_int func go_callback_int(foo C.int, p1 C.int) { fn := lookup(int(foo)) fn(p1) } func MyCallback(x C.int) { fmt.Println("callback with", x) } func Example() { i := register(MyCallback) C.go_callback_int(C.int(i), 5) unregister(i) } func main() { Example() }</code>
此解决方案遵循更新的 wiki 页面,提供了在当前 cgo 约束内将函数指针传递给 C 代码的稳健方法。
以上是Go v1.6 之后如何使用 cgo 将函数指针传递给 C 代码?的详细内容。更多信息请关注PHP中文网其他相关文章!