ホームページ >バックエンド開発 >Golang >Go 1.6 以降で Cgo を使用して関数ポインタを C コードに渡すにはどうすればよいですか?

Go 1.6 以降で Cgo を使用して関数ポインタを C コードに渡すにはどうすればよいですか?

Linda Hamilton
Linda Hamiltonオリジナル
2024-10-30 17:46:31781ブラウズ

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

Cgo を使用した C コードへの関数ポインタの受け渡し

Cgo 関数ポインタの受け渡しの変更

Go 1.6 以降では、Cgo の受け渡しに関するより厳格なルールがあります。 C コードへのポインタ。 Go ポインターを含む Go メモリを指す Go ポインターを渡すことはできなくなりました。

コード例

次の Go コードは、関数ポインターを 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>

エラーと解決策

MyCallbackFunc が指す Go メモリには Go 関数ポインター (MyCallback) が含まれているため、このコードを実行するとエラーが発生します。

Toこれに対処するには、新しいルールに違反せずに関数ポインタを C コードに渡す方法を見つける必要があります。

ポインタの代わりに ID を使用する

1 つのアプローチこれは、関数ポインタを同期されたデータ構造に格納し、直接ポインタの代わりに ID を C コードに渡すことです。このように、C コードは ID を使用して、データ構造を通じて関数ポインターにアクセスできます。

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>

以上がGo 1.6 以降で Cgo を使用して関数ポインタを C コードに渡すにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。