Home  >  Article  >  Backend Development  >  How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?

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

Linda Hamilton
Linda HamiltonOriginal
2024-10-30 17:46:31698browse

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

Passing Function Pointer to C Code Using Cgo

Changes in Cgo Function Pointer Passing

In Go 1.6 and later, Cgo has stricter rules for passing pointers to C code. It is no longer allowed to pass a Go pointer that points to Go memory containing any Go pointers.

Code Example

The following Go code demonstrates how to pass a function pointer to C code:

<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>

Error and Solution

When running this code, it produces an error because the Go memory pointed to by MyCallbackFunc contains a Go function pointer (MyCallback).

To address this, we need to find a way to pass the function pointer to C code without violating the new rules.

Using an ID Instead of a Pointer

One approach is to store the function pointer in a synchronized data structure and pass an ID to the C code instead of a direct pointer. This way, the C code can use the ID to access the function pointer through the data structure.

Code with ID-Based Function Pointer Passing

<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>

The above is the detailed content of How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn