Cgo中将C函数返回的数组转为Go中的slice

本文探讨了在Go中如何调用C动态库的target detection函数,特别关注了处理二级指针和内存转换的挑战,以及作者对protobuf序列化的使用偏好。

之前在go服务中,要调用同事动态库中的一个目标检测函数:

typedef struct {
    int x;
    int y;
    int width;
    int height;
} HRect;

LIB_EXPORT int detect_objects(void *ptr, const char *imgPath, HRect srect, HRect **rrects, int *rsize);

其中第四个参数,需要我传递一个区域参数的二级指针,动态库中分配内存、计算目标检测的结果区域,并返回结果大小。即我需要将C函数返回的数组,转为go中的slice。

转换代码如下:

type AlgoRect struct {
	X      int `json:"x"`
	Y      int `json:"y"`
	Width  int `json:"width"`
	Height int `json:"height"`
}

func algoProcess(img string, rect AlgoRect) (err error, rects []AlgoRect) {
    var cRect C.HRect
    var cRects *C.HRect
    var cInt C.int

    cRect.x = 1
    cRect.y = 2
    cRect.width = 3
    cRect.height = 4

    ret := C.detect_objects(gAlgoHandler, cimg, cRect, &cRects, &cInt)
    unsafePtr := unsafe.Pointer(cRects)
    goInt := int(cInt)
    defer C.free(unsafePtr)

    arrayPtr := (*[1 << 30]C.HRect)(unsafePtr)
    goSlice := arrayPtr[0:goInt:goInt]
    algoRet := make([]AlgoRect, 0)
    for _, v := range goSlice {
	    algoRet = append(algoRet, AlgoRect{
		    X:      int(v.x),
		    Y:      int(v.y),
		    Width:  int(v.width),
		    Height: int(v.height),
	    })
    }
    return nil, algoRet
}

省略了一些不关键的代码。

在调用完C函数之后,结果保存在cRects指向的C分配的内存之中,需要将这块内存中的内容,拷贝为Go的slice(不要忘记用C的free释放掉这块内存)。

第一步是将cRects做一个类型转换,由C数组转为Go的array,然后根据出参cInt,得到正确大小的slice,这样才能用循环将其拷贝到新的、由go管理内存的slice当中。

可以看到,cgo的一些转换还是稍微有些麻烦的。之前项目中,我更喜欢的方式是将go服务层的调用参数通过protobuf序列化,将序列化后的地址void*和其长度传递到动态库中,动态库中反序列化得到参数。虽然引入了protobuf,但是一劳永逸,避免了经常写cgo。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值