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

Go  同时被 3 个专栏收录
0 篇文章 0 订阅
1 篇文章 0 订阅
1 篇文章 0 订阅

经常可以遇到这样的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 <stdlib.h>
#include <string.h>

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/

  • 0
    点赞
  • 4
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论 4 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

startAt24

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值