"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Como passar ponteiros de função para código C usando Cgo no Go 1.6 e posterior?

Como passar ponteiros de função para código C usando Cgo no Go 1.6 e posterior?

Publicado em 2024-11-09
Navegar:735

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

Passando o ponteiro de função para o código C usando Cgo

Alterações na passagem do ponteiro de função Cgo

No Go 1.6 e posterior, o Cgo tem regras mais rígidas para aprovação ponteiros para código C. Não é mais permitido passar um ponteiro Go que aponte para a memória Go contendo quaisquer ponteiros Go.

Exemplo de código

O código Go a seguir demonstra como passar um ponteiro de função para o código 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()
}

Erro e solução

Ao executar este código, ele produz um erro porque a memória Go apontada por MyCallbackFunc contém um ponteiro de função Go (MyCallback).

Para endereçar Para fazer isso, precisamos encontrar uma maneira de passar o ponteiro de função para o código C sem violar as novas regras.

Usando um ID em vez de um ponteiro

Uma abordagem é armazenar o ponteiro de função em uma estrutura de dados sincronizada e passar um ID para o código C em vez de um ponteiro direto. Dessa forma, o código C pode usar o ID para acessar o ponteiro de função por meio da estrutura de dados.

Código com passagem de ponteiro de função baseada em 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)
}
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3