passing function pointer to the C code using cgo

后端 未结 2 1281
囚心锁ツ
囚心锁ツ 2021-02-06 04:04

Starting from Go v1.6 cgo changed the rules of passing pointers to the C code golang/go#12416. The example of invoking a dynamic Go callback from C code from the wiki doesn\'t

2条回答
  •  天命终不由人
    2021-02-06 04:52

    It depends exactly what you need to do with the callback function - but a trick that might work is to not pass the Go function, but a pointer to a struct with the function on it that you want.

    For example:

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    /*
    extern void go_callback_int(void*, int);
    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 := (*Test)(pfoo)
        foo.cb(p1)
    }
    
    type Test struct {
    }
    
    func (s *Test) cb(x C.int) {
        fmt.Println("callback with", x)
    }
    
    func main() {
        data := &Test{}
        C.CallMyFunction(unsafe.Pointer(&data))
    }
    

    Another option might be to use a global variable as you had in your example, and then forgo passing anything useful in the pointer to C.

    Like this:

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    /*
    extern void go_callback_int(void*, int);
    static inline void CallMyFunction(void* pfoo) {
        go_callback_int(pfoo, 5);
    }
    */
    import "C"
    
    //export go_callback_int
    func go_callback_int(_ unsafe.Pointer, p1 C.int) {
        MyCallbackFunc(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 main() {
        C.CallMyFunction(nil)
    }
    

    It possibly depends on what your C callback needs to do.

    If neither of these work it might be possible to do some tricks with channels to send the value you need (and keep it in scope).

提交回复
热议问题