在Go 1.6 及更高版本中,Cgo 對於傳遞有更嚴格的規則指向C 代碼的指標。不再允許傳遞指向包含任何 Go 指標的 Go 記憶體的 Go 指標。
以下 Go 程式碼示範如何將函數指標傳遞給 C 程式碼:
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()
}
運行這段程式碼時,會產生錯誤,因為MyCallbackFunc指向的Go記憶體中包含一個Go函數指標(MyCallback)。
要地址為此,我們需要找到一種方法將函數指標傳遞給 C 程式碼而不違反新規則。
使用 ID 而不是指標
一種方法是將函數指標儲存在同步資料結構中,並將 ID 傳遞給 C 程式碼而不是直接指標。這樣,C 程式碼就可以使用 ID 透過資料結構存取函數指標。
基於 ID 的函數指標傳遞的程式碼
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)
}
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3