简体   繁体   English

将结构数组从 C++ 传递到 GO

[英]Pass array of structs from C++ to GO

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.我正在尝试从 C++ 到 golang 获取一系列 tensorflow 框预测,但无论我做什么,我都无法做到。 I have a GO program that calls a function that does tensorflow detections in C++ using cgo.我有一个 GO 程序,它调用一个函数,该函数使用 cgo 在 C++ 中进行张量流检测。 This all works and I'm able to get the predictions in C++.这一切都有效,我能够在 C++ 中获得预测。 The problem is to transfer these predictions into GO as an array of 100 structs that each hold one prediction.问题是将这些预测作为 100 个结构的数组转移到 GO 中,每个结构包含一个预测。

I'm able to set a pointer in GO and use this pointer address to set one struct in C++.我可以在 GO 中设置一个指针并使用这个指针地址在 C++ 中设置一个结构。 The code for this is seen below.代码如下所示。

I want to set an array of structs in C++ and retreive this array in GO.我想在 C++ 中设置一个结构数组并在 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.我认为使用与之前相同的指针地址并将其用作我的 C++ 数组的地址应该很容易。 Then I could restore the struct from the pointer in GO.然后我可以从 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}

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:假设您的 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;
// }
//
//
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.您最感兴趣的是如何将getTenResults的结果转换为适当结构类型的 Go 切片。 This is employing the technique recommended on the Go wiki .这是采用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.根据您的 C 函数的确切签名,您可能需要在import "C"部分编写一个“桥接”函数,以便为 Go 提供方便的数据,但这是它的基本要点。

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:作为替代方案,如果您希望在 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"

And then in Go do:然后在 Go 中:

prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)

Of course the hard-coded 10 is just for simplicity here;当然,这里硬编码的 10 只是为了简单起见; you could pass the length of arr as a parameter to C.您可以将arr的长度作为参数传递给 C。

您可以将指向切片中第一个元素的指针和切片的长度传递给 C++,并将其视为 C 风格的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM