首页  >  文章  >  后端开发  >  如何在 Go 1.6 及更高版本中使用 Cgo 将函数指针传递给 C 代码?

如何在 Go 1.6 及更高版本中使用 Cgo 将函数指针传递给 C 代码?

Linda Hamilton
Linda Hamilton原创
2024-10-30 17:46:31698浏览

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 代替指针

一种方法是将函数指针存储在同步数据结构中,并将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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn