В 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()
}
При запуске этого кода выдается ошибка, поскольку память Go, на которую указывает MyCallbackFunc, содержит указатель на функцию Go (MyCallback).
По адресу Для этого нам нужно найти способ передать указатель функции в код C, не нарушая новых правил.
Использование идентификатора Вместо указателя
Один подход — сохранить указатель функции в синхронизированной структуре данных и передать идентификатор в код C вместо прямого указателя. Таким образом, код C может использовать идентификатор для доступа к указателю функции через структуру данных.
Код с передачей указателя функции на основе идентификатора
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