从Go 1.6 cgo开始有新的规则.
Go code may pass a Go pointer to C provided that the Go memory to which it points does not contain any Go pointers.
在运行时期间检查这些规则,如果违反了程序崩溃.目前,可以使用GODEBUG = cgocheck = 0环境变量禁用检查.但在未来可能会停止工作.
因此,如果指向它的内存存储Go函数/方法指针,则不可能再传递指向C代码的指针.有几种方法可以克服这些限制,但我想在大多数方法中你应该存储一个同步数据结构,它代表某个id和实际指针之间的对应关系.这样您就可以将id传递给C代码,而不是指针.
解决此问题的代码可能如下所示:
package gocadllback
import (
"fmt"
"sync"
)
/*
extern void go_callback_int(int foo, int p1);
// normally you will have to define function or variables
// in another separate C file to avoid the multiple definition
// errors, however, using "static inline" is a nice workaround
// for simple functions like this one.
static inline void CallMyFunction(int foo) {
go_callback_int(foo, 5);
}
*/
import "C"
//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.CallMyFunction(C.int(i))
unregister(i)
}
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)
}
此代码来自(已更新)wiki page.