英文:
Pass array of structs from C++ to GO
问题
我正在尝试将一个由C++生成的TensorFlow盒子预测数组传递给Golang,但无论我怎么做都无法成功。我有一个Golang程序,调用一个使用cgo在C++中进行TensorFlow检测的函数。这一切都正常工作,我能够在C++中获取到预测结果。问题是如何将这些预测结果作为一个包含100个结构体的数组传递给Golang。
我能够在Golang中设置一个指针,并使用该指针地址在C++中设置一个结构体。下面是这部分代码:
type PredictResult struct {
Loc [4]float32
Score int
Label int
}
var predictions PredictResult
predictions_ptr := unsafe.Pointer(&predictions)
C.LIB_predict(predictions_ptr)
fmt.Println("GO predictions: ", predictions)
bridge.hpp
struct PredictResult{
float Loc[4];
int64_t Score;
int64_t Label;
};
void LIB_predict(void* predictions);
bridge.cpp
void LIB_predict(void* predictions){
PredictResult *p = (PredictResult*)predictions;
p->Score = 6;
p->Label = 95;
}
打印结果为:
GO predictions: {[0 0 0 0] 6 95}
我想在C++中设置一个结构体数组,并在Golang中获取这个数组。我认为只需要使用之前的指针地址作为C++数组的地址,然后在Golang中通过指针恢复结构体即可。有人对此有解决方案吗?
英文:
I'm trying to get an array of tensorflow box predictions from C++ to golang, but I'm not able to do it no matter what I do. I have a GO program that calls a function that does tensorflow detections in C++ using cgo. This all works and I'm able to get the predictions in C++. The problem is to transfer these predictions into GO as an array of 100 structs that each hold one prediction.
I'm able to set a pointer in GO and use this pointer address to set one struct in C++. The code for this is seen below.
I want to set an array of structs in C++ and retreive this array in GO. I thought it should be easy to just use the same pointer address as earlier and use this as the address for my C++ array. Then I could restore the struct from the pointer in GO. Does anyone have a solution for this?
GO
type PredictResult struct {
Loc [4]float32
Score int
Label int
}
var predictions PredictResult
predictions_ptr := unsafe.Pointer(&predictions)
C.LIB_predict(predictions_ptr)
fmt.Println("GO predictions; ", predictions)
bridge.hpp
struct PredictResult{
float Loc[4];
int64_t Score;
int64_t Label;
};
void LIB_predict(void* predictions);
bridge.cpp
void LIB_predict(void* predictions){
PredictResult *p = (PredictResult*)predictions;
p->Score = 6;
p->Label = 95;
}
Prints:
GO predictions; {[0 0 0 0] 6 95}
答案1
得分: 2
假设你的C函数返回类型为PredictResult*
的数组,并且假设你知道返回数组的长度(在下面的示例中,我假设长度为10,但你可以根据实际情况进行替换),这种方法应该可以工作:
#include <stdio.h>
#include <stdlib.h>
typedef struct PredictResult {
float Loc[4];
int64_t Score;
int64_t Label;
} PredictResult;
PredictResult* getOneResult() {
PredictResult* p = (PredictResult*)calloc(1, sizeof(PredictResult));
p->Score = 10;
p->Label = 99;
p->Loc[1] = 2.5;
p->Loc[3] = 3.5;
return p;
}
PredictResult* getTenResults() {
PredictResult* parr = (PredictResult*)calloc(10, sizeof(PredictResult));
parr[0].Score = 10;
parr[0].Label = 99;
parr[0].Loc[1] = 2.5;
parr[0].Loc[3] = 3.5;
parr[4].Score = 44;
parr[4].Label = 123;
parr[4].Loc[1] = 12.25;
parr[4].Loc[3] = -40.5;
return parr;
}
你最感兴趣的是如何将getTenResults
的结果转换为适当结构类型的Go切片。这里使用了Go维基上推荐的技术。
根据你的C函数的确切签名,你可能需要在import "C"
部分编写一个“桥接”函数,以便将数据方便地提供给Go,但这是基本的要点。
作为另一种选择,如果你希望在Go端分配切片并传入指向C的指针进行填充,可以这样做:
void PopulateTenResults(void* arr) {
PredictResult* parr = (PredictResult*)arr;
parr[1].Score = 210;
parr[1].Label = 299;
parr[1].Loc[1] = 22.5;
parr[1].Loc[3] = 23.5;
parr[8].Score = 344;
parr[8].Label = 3123;
parr[8].Loc[1] = 312.25;
parr[8].Loc[3] = -340.5;
}
然后在Go中执行以下操作:
prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)
当然,这里的硬编码的10只是为了简单起见;你可以将arr
的长度作为参数传递给C函数。
英文:
Assuming your C function returns the array as PredictResult*
and assuming you know the length of the returned array (in the example below I assume 10, but you can replace it by whatever works), this approach should work:
// #include <stdio.h>
// #include <stdlib.h>
//
// typedef struct PredictResult {
// float Loc[4];
// int64_t Score;
// int64_t Label;
// } PredictResult;
//
// PredictResult* getOneResult() {
// PredictResult* p = (PredictResult*)calloc(1, sizeof(PredictResult));
// p->Score = 10;
// p->Label = 99;
// p->Loc[1] = 2.5;
// p->Loc[3] = 3.5;
// return p;
// }
//
// PredictResult* getTenResults() {
// PredictResult* parr = (PredictResult*)calloc(10, sizeof(PredictResult));
// parr[0].Score = 10;
// parr[0].Label = 99;
// parr[0].Loc[1] = 2.5;
// parr[0].Loc[3] = 3.5;
//
// parr[4].Score = 44;
// parr[4].Label = 123;
// parr[4].Loc[1] = 12.25;
// parr[4].Loc[3] = -40.5;
// return parr;
// }
//
//
import "C"
type PredictResult C.struct_PredictResult
func main() {
p := C.getOneResult()
if p == nil {
log.Fatal("got nil")
}
pp := (*PredictResult)(p)
fmt.Println(pp)
parr := C.getTenResults()
if parr == nil {
log.Fatal("got nil")
}
pslice := (*[1 << 28]PredictResult)(unsafe.Pointer(parr))[:10:10]
fmt.Println(pslice)
}
What you'll be most interested in is how the result of getTenResults
is converted to a Go slice of the appropriate struct type. This is employing the technique recommended on the Go wiki.
Depending on the exact signature of your C function you may need to write a "bridge" function in the import "C"
part to provide the data as convenient to Go, but this is the basic gist of it.
As an alternative, if you wish to allocate the slice on the Go side and pass in a pointer to C to populate, you can do this:
// void PopulateTenResults(void* arr) {
// PredictResult* parr = (PredictResult*)arr;
// parr[1].Score = 210;
// parr[1].Label = 299;
// parr[1].Loc[1] = 22.5;
// parr[1].Loc[3] = 23.5;
//
// parr[8].Score = 344;
// parr[8].Label = 3123;
// parr[8].Loc[1] = 312.25;
// parr[8].Loc[3] = -340.5;
// }
//
//
import "C"
And then in Go do:
prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)
Of course the hard-coded 10 is just for simplicity here; you could pass the length of arr
as a parameter to C.
答案2
得分: 1
你可以将切片的第一个元素的指针和切片的长度传递给C++,并将其视为C风格的数组。
英文:
You can pass a pointer to the first element in a slice and the length of the slice to C++ and treat it like a C-style array.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论