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

1338

被折叠的 条评论
为什么被折叠?



