cgo直接调用函数,使用基本数据类型非常简单,包括一些结构体也比较简单,嵌套的稍微复杂些,但也可以,但有的时候,cgo调用c函数,会需要传递一个回调函数的指针,这时候就比较复杂了,要比python的ctypes复杂很多,python可以用winfunc很轻松去创建这样的函数,但是对于 go 这种编译型语言来说,就很麻烦了,实际上是如下操作:
先看官方代码:
这块是头文件的声明
一、构造包装函数(callOnMeGo_cgo),这里通过cgo编写一个自己的c函数,满足要调用库的callback格式就可以。
这里int callOnMeGo(int);的函数声明,可以放到函数体外面去,便于查看。
如果只需要结构体某些字段,可以直接在这里提取后转发过去,省略了Go语言中操作的步骤。
二、用包装函数调用真正的go函数(callOnMeGo),然后就可以实现回调了
这里主入口,记得声明下包装函数的结构;
问题解决:
1.传参后,回调函数调用没效果:
一般这种都是回调函数的参数类型不对,比如说void *传unsafe.pointer是可以的;但是结构体指针不能传unsafe.pointer,可直接声明C.STRUCTXXX,是指针就传* C.STRUCTXXXX
注意,回调参数有问题, 请看下引用的C或者C++ SDK 自己的日志,go程序是不会有任何反应的。
2.编译报错
编译报错需要检查
①.是否注释内部有嵌套,有的需要删掉或者拿出去
②.头文件的struct是否带 tag 不带tag 需要增加
③. 是否出现了释放不该释放的内容,比如说,回调传过来的结构体,通过var声明后,就进入到了Go的GC范围内,不要去C.free
④.是否有C++的东西,如果有C++的东西需要转换成C语言
⑤.编译的平台需要一致,编译时,需要编译整个package;64位的lib,需要 64 位的cgo编译
⑥.编译后导入表会对指定函数有强依赖,必须带入依赖库,运行时不像syscall可以懒加载。
⑦.CFLAGS、LDFLAGS的参数是否完整,比如说没有使用-l指定对应的lib