Go 通过Cgo传递函数指针给 C函数。 来设置回调函数。将void*转为[]byte获取数据。

经常可以遇到这样的SDK,需要传递一个回调函数。例如:
通过回调的方式将数据返回给调用者。 在回调结束之后 void* a 里存的数据就会被释放。
test.h

#ifndef __TEST_H__
#define __TEST_H__
#ifdef __cplusplus
extern "C"{
#endif

#define API __attribute__((visibility("default")))

typedef struct info{
    void* a;
    int  size;
}tInfo;

typedef int(*cb) (tInfo* n);


API int setcallback(cb s);

API void call();

API void clean();

#ifdef __cplusplus
}
#endif
#endif

test.c

#include "test.h"
#include 
#include 

cb gS;
tInfo info;

int setcallback(cb s){
    gS = s;
    info.a = malloc(3);
    info.size = 3;
    char t[3] = "abc";
    memcpy(info.a, t, 3);
    return 1;
}

void call(){
    gS(&info);
}

void clean(){
    free(info.a);
}

下面就是在Go中调用他的方法。

package main

/*
#cgo CFLAGS: -I./
#cgo LDFLAGS:-Wl,-rpath,./
#cgo LDFLAGS: -L./ -ltest
#include "test.h"
int testCB(struct info *);
*/
import "C"
import "fmt"
import "unsafe"
var tmp = make([] byte, 4)

func main(){
	C.setcallback(C.cb(C.testCB))
	C.call()
	C.clean()
	fmt.Println(tmp)
}
//export testCB
func testCB(info *C.struct_info) C.int{
	tmp = C.GoBytes(unsafe.Pointer(info.a), info.size)
	return 1
}

运行go run main.go 可以得到这样的结果[97 98 99]。 调用成功。

注意!import "C“ 上面的注释必须有! 具体每一行的意思可以查找Cgo教程。 回调使用的函数 testCB 上面的 //export testCB 也是必须的!
将C里申请的内存转到GO这里,需要使用C.GoBytes 这里实际做了一次拷贝,这样之后的内存就有Go的GC去管理了。

如果代码中使用到了 C.CString() 将 Go的String 转换成 C的 char*, 必须使用 C.free(unsafe.Pointer()) 去释放。
例子:

file_name := C.CString(go_file_name)
sdk_ret := C.sdk_init(file_name)
defer C.free(unsafe.Pointer(file_name))

参考: https://golang.org/cmd/cgo/

你可能感兴趣的:(Go,Cgo,Callback)