Maison >développement back-end >Golang >Comment transmettre des pointeurs de fonction au code C à l'aide de Cgo dans Go 1.6 et versions ultérieures ?

Comment transmettre des pointeurs de fonction au code C à l'aide de Cgo dans Go 1.6 et versions ultérieures ?

Linda Hamilton
Linda Hamiltonoriginal
2024-10-30 17:46:31775parcourir

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

Passage du pointeur de fonction vers le code C à l'aide de Cgo

Modifications dans le passage du pointeur de fonction Cgo

Dans Go 1.6 et versions ultérieures, Cgo a des règles plus strictes pour le passage pointeurs vers le code C. Il n'est plus autorisé de transmettre un pointeur Go qui pointe vers la mémoire Go contenant des pointeurs Go.

Exemple de code

Le code Go suivant montre comment passer un pointeur de fonction vers le code C :

<code class="go">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(&amp;MyCallbackFunc))
}

func main() {
    Example()
}</code>

Erreur et solution

Lors de l'exécution de ce code, il produit une erreur car la mémoire Go pointée par MyCallbackFunc contient un pointeur de fonction Go (MyCallback).

À Pour résoudre ce problème, nous devons trouver un moyen de transmettre le pointeur de fonction au code C sans enfreindre les nouvelles règles.

Utiliser un identifiant au lieu d'un pointeur

Une approche consiste à stocker le pointeur de fonction dans une structure de données synchronisée et à transmettre un identifiant au code C au lieu d'un pointeur direct. De cette façon, le code C peut utiliser l'ID pour accéder au pointeur de fonction via la structure de données.

Code avec passage du pointeur de fonction basé sur l'ID

<code class="go">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)
}</code>

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn