Home > Article > Backend Development > How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?
In Go 1.6 and later, Cgo has stricter rules for passing pointers to C code. It is no longer allowed to pass a Go pointer that points to Go memory containing any Go pointers.
The following Go code demonstrates how to pass a function pointer to C code:
<code class="go">import ( "fmt" "unsafe" ) /* extern void go_callback_int(void* foo, int p1); static inline void CallMyFunction(void* pfoo) { go_callback_int(pfoo, 5); } */ import "C" //export go_callback_int func go_callback_int(pfoo unsafe.Pointer, p1 C.int) { foo := *(*func(C.int))(pfoo) foo(p1) } func MyCallback(x C.int) { fmt.Println("callback with", x) } // we store it in a global variable so that the garbage collector // doesn't clean up the memory for any temporary variables created. var MyCallbackFunc = MyCallback func Example() { C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc)) } func main() { Example() }</code>
When running this code, it produces an error because the Go memory pointed to by MyCallbackFunc contains a Go function pointer (MyCallback).
To address this, we need to find a way to pass the function pointer to C code without violating the new rules.
Using an ID Instead of a Pointer
One approach is to store the function pointer in a synchronized data structure and pass an ID to the C code instead of a direct pointer. This way, the C code can use the ID to access the function pointer through the data structure.
Code with ID-Based Function Pointer Passing
<code class="go">package gocallback import ( "fmt" "sync" ) /* extern void go_callback_int(int foo, int p1); 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) }</code>
The above is the detailed content of How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?. For more information, please follow other related articles on the PHP Chinese website!