【问题标题】:Pass array of structs from C++ to GO将结构数组从 C++ 传递到 GO
【发布时间】:2021-09-13 00:13:12
【问题描述】:

我正在尝试从 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++ arrays c go cgo


    【解决方案1】:

    假设您的 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)
    }
    

    您最感兴趣的是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。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-01
        • 2011-01-19
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多