„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Wie übergebe ich Funktionszeiger an C-Code mit Cgo in Go 1.6 und höher?

Wie übergebe ich Funktionszeiger an C-Code mit Cgo in Go 1.6 und höher?

Veröffentlicht am 09.11.2024
Durchsuche:376

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

Übergabe eines Funktionszeigers an C-Code mit Cgo

Änderungen bei der Übergabe von Cgo-Funktionszeigern

In Go 1.6 und höher gelten für Cgo strengere Regeln für die Übergabe Zeiger auf C-Code. Es ist nicht länger zulässig, einen Go-Zeiger zu übergeben, der auf einen Go-Speicher verweist, der Go-Zeiger enthält.

Codebeispiel

Der folgende Go-Code zeigt, wie ein Funktionszeiger an C-Code übergeben wird:

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()
}

Fehler und Lösung

Beim Ausführen dieses Codes wird ein Fehler erzeugt, da der Go-Speicher, auf den MyCallbackFunc zeigt, einen Go-Funktionszeiger (MyCallback) enthält.

Zur Adresse Dazu müssen wir einen Weg finden, den Funktionszeiger an C-Code zu übergeben, ohne die neuen Regeln zu verletzen.

Verwenden einer ID anstelle eines Zeigers

Ein Ansatz ist um den Funktionszeiger in einer synchronisierten Datenstruktur zu speichern und anstelle eines direkten Zeigers eine ID an den C-Code zu übergeben. Auf diese Weise kann der C-Code die ID verwenden, um über die Datenstruktur auf den Funktionszeiger zuzugreifen.

Code mit ID-basierter Funktionszeigerübergabe

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)
}
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3