将结构数组从 C++ 传递到 GO
Pass array of structs from C++ to GO
我正在尝试从 C++ 到 golang 获取一系列 tensorflow 框预测,但无论我做什么我都无法做到。我有一个 GO 程序调用一个函数,该函数使用 cgo 在 C++ 中进行张量流检测。这一切都有效,我能够在 C++ 中获得预测。问题是将这些预测作为 100 个结构的数组传输到 GO,每个结构包含一个预测。
我可以在 GO 中设置一个指针,并使用这个指针地址在 C++ 中设置一个结构。代码如下所示。
我想在 C++ 中设置一个结构数组,然后在 GO 中检索这个数组。我认为使用与之前相同的指针地址并将其用作我的 C++ 数组的地址应该很容易。然后我可以从 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;
}
打印:
GO predictions; {[0 0 0 0] 6 95}
您可以将指向切片中第一个元素的指针和切片的长度传递给 C++,并将其视为 C 样式数组。
假设您的 C 函数 returns 数组为 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;
// }
//
//
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)
}
您最感兴趣的是 getTenResults
的结果如何转换为适当结构类型的 Go 切片。这是在使用 technique recommended on the Go wiki.
根据您的 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;
// }
//
//
import "C"
然后在 Go 中执行:
prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)
当然,硬编码的 10 只是为了简单起见;您可以将 arr
的长度作为参数传递给 C.
我正在尝试从 C++ 到 golang 获取一系列 tensorflow 框预测,但无论我做什么我都无法做到。我有一个 GO 程序调用一个函数,该函数使用 cgo 在 C++ 中进行张量流检测。这一切都有效,我能够在 C++ 中获得预测。问题是将这些预测作为 100 个结构的数组传输到 GO,每个结构包含一个预测。
我可以在 GO 中设置一个指针,并使用这个指针地址在 C++ 中设置一个结构。代码如下所示。
我想在 C++ 中设置一个结构数组,然后在 GO 中检索这个数组。我认为使用与之前相同的指针地址并将其用作我的 C++ 数组的地址应该很容易。然后我可以从 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;
}
打印:
GO predictions; {[0 0 0 0] 6 95}
您可以将指向切片中第一个元素的指针和切片的长度传递给 C++,并将其视为 C 样式数组。
假设您的 C 函数 returns 数组为 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;
// }
//
//
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)
}
您最感兴趣的是 getTenResults
的结果如何转换为适当结构类型的 Go 切片。这是在使用 technique recommended on the Go wiki.
根据您的 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;
// }
//
//
import "C"
然后在 Go 中执行:
prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)
当然,硬编码的 10 只是为了简单起见;您可以将 arr
的长度作为参数传递给 C.