«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Как передать указатели на функции в код C с помощью Cgo в Go 1.6 и более поздних версиях?

Как передать указатели на функции в код C с помощью Cgo в Go 1.6 и более поздних версиях?

Опубликовано 9 ноября 2024 г.
Просматривать:532

How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?

Передача указателя функции в код C с использованием Cgo

Изменения в передаче указателя функции Cgo

В 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