cgo を使用して関数ポインターを C コードに渡す
Go v1.6 より前の cgo では、Go ポインターを C コードに渡すことができました。ただし、v1.6 で実装された変更の後、ポインタを渡すためのルールが大幅に変更されました。この変更により、C コードから動的 Go コールバックを呼び出すために以前に使用されていた方法が無効になりました。
問題の説明
コード サンプル (かつては Go コールバックを呼び出す機能例) C から実行すると、実行時エラーが発生します:
panic: runtime error: cgo argument has Go pointer to Go pointer
ソリューション
新しい cgo ルールでは、Go コードは、次の場合にのみ Go ポインタを C に渡すことができます。それが指す Go メモリには Go ポインタが含まれていません。この制限により、指定されたメモリに Go 関数/メソッド ポインタが格納されている場合、ポインタを C コードに渡すことができなくなります。
この制限を克服するには、いくつかのアプローチが考えられます。一般的な解決策には、特定の ID と実際のポインタの間の対応を確立する同期データ構造を保存することが含まれます。ポインターの代わりに ID を C コードに渡すことで、制限が回避されます。
このソリューションを紹介する更新されたコード サンプル:
<code class="go">package gocallback import ( "fmt" "sync" ) /* extern void go_callback_int(int foo, int p1); */ import "C" 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) } //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.go_callback_int(C.int(i), 5) unregister(i) } func main() { Example() }</code>
このソリューションは、更新された Wiki ページに従っており、現在の cgo 制約内で関数ポインタを C コードに渡すための堅牢なアプローチ。
以上がGo v1.6 以降、cgo を使用して関数ポインターを C コードに渡す方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。