mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
Updated cgo (markdown)
parent
d36665219f
commit
19c2987db4
48
cgo.md
48
cgo.md
@ -79,45 +79,67 @@ void ACFunction() {
|
|||||||
|
|
||||||
### Function variables
|
### Function variables
|
||||||
|
|
||||||
The following code shows an example of invoking a Go callback from C code. Go passes the function variable to the CGo code by calling ` CallMyFunction() `. ` CallMyFunction() ` invokes the callback by sending it back into the Go code, with the desired parameters, for unpacking and calling.
|
The following code shows an example of invoking a Go callback from C code. Because of the [pointer passing rules](https://golang.org/cmd/cgo/#hdr-Passing_pointers) Go code can not pass a function value directly to C. Instead it is necessary to use an indirection. This example uses a registry with a mutex, but there are many other ways to map from a value that can be passed to C to a Go function.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package gocallback
|
package gocallback
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
extern void go_callback_int(void* foo, int p1);
|
extern void go_callback_int(int foo, int p1);
|
||||||
|
|
||||||
// normally you will have to define function or variables
|
// normally you will have to define function or variables
|
||||||
// in another separate C file to avoid the multiple definition
|
// in another separate C file to avoid the multiple definition
|
||||||
// errors, however, using "static inline" is a nice workaround
|
// errors, however, using "static inline" is a nice workaround
|
||||||
// for simple functions like this one.
|
// for simple functions like this one.
|
||||||
static inline void CallMyFunction(void* pfoo) {
|
static inline void CallMyFunction(int foo) {
|
||||||
go_callback_int(pfoo, 5);
|
go_callback_int(foo, 5);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
//export go_callback_int
|
//export go_callback_int
|
||||||
func go_callback_int(pfoo unsafe.Pointer, p1 C.int) {
|
func go_callback_int(foo C.int, p1 C.int) {
|
||||||
foo := *(*func(C.int))(pfoo)
|
fn := lookup(int(foo))
|
||||||
foo(p1)
|
fn(p1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MyCallback(x C.int) {
|
func MyCallback(x C.int) {
|
||||||
fmt.Println("callback with", x)
|
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() {
|
func Example() {
|
||||||
C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))
|
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++
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user