"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > ¿Cómo pasar punteros de función al código C usando Cgo en Go 1.6 y versiones posteriores?

¿Cómo pasar punteros de función al código C usando Cgo en Go 1.6 y versiones posteriores?

Publicado el 2024-11-09
Navegar:630

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

Pasar el puntero de función al código C usando Cgo

Cambios en el paso del puntero de función de Cgo

En Go 1.6 y posteriores, Cgo tiene reglas más estrictas para pasar punteros al código C. Ya no está permitido pasar un puntero de Go que apunte a la memoria de Go que contenga punteros de Go.

Ejemplo de código

El siguiente código de Go demuestra cómo pasar un puntero de función al 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()
}

Error y solución

Al ejecutar este código, se produce un error porque la memoria Go a la que apunta MyCallbackFunc contiene un puntero de función Go (MyCallback).

Para abordar Para esto, necesitamos encontrar una manera de pasar el puntero de función al código C sin violar las nuevas reglas.

Usar una identificación en lugar de un puntero

Un enfoque es para almacenar el puntero de función en una estructura de datos sincronizada y pasar una ID al código C en lugar de un puntero directo. De esta manera, el código C puede usar la ID para acceder al puntero de función a través de la estructura de datos.

Código con puntero de función basado en ID pasando

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)
}
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3