经常可以遇到这样的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/