【问题标题】:How to return struct from CGO如何从 CGO 返回结构
【发布时间】:2020-10-28 14:23:13
【问题描述】:

我想从 C 中调用一个返回结构的 Go 函数,并且在 C 中我想处理该结构。

目标是用数据填充结构并返回信息。我不知道哪种格式最好通过。我需要在 C 代码中获取有关返回数据长度的信息,以及结构的每个 strl 值。

(我调用的函数不是strings.Split())。它更复杂,但我需要的返回值是char*int

我的 Go 源代码:

package main

import "C"
import (
    "fmt"
    "strings"
)


type retvalue struct {
    str *C.char
    l   int
}

// This is what I want to achieve (or something similar):
// func Split(input *C.char) []retvalue {
//    ...
//    ...
//    return ret
// }

//export Split
func Split(input *C.char) {
    all := strings.Split(C.GoString(input), ",")
    ret := []retvalue{}
    for _, str := range all {
        ret = append(ret, retvalue{str: C.CString(str), l: len(str)})
    }
    fmt.Printf("%#v\n", ret)
    // return ret
}

func main() {}

这是我的 C 代码:

#include "libsplitter.h"

int main(int argc, char const *argv[])
{
    char* input="Hello,nice,world";
    Split(input);
    // do something with the return values from my Split()
    return 0;
}

我编译并运行代码(在 macOS 上)

go build -o libsplitter.dylib -buildmode=c-shared main.go
cc splitit.c -o splitit -lsplitter -L.
LD_LIBRARY_PATH=$PWD ./splitit

【问题讨论】:

    标签: struct shared-libraries cgo


    【解决方案1】:

    我找到了解决办法。

    我的 C 文件:

    #include "libsplitter.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char const *argv[]) {
        struct splitvalues* sv;
        sv = Split("hello,nice,world",",");
    
        printf("%d\n",sv->count);
        char** cptr = sv->splitted;
        int *i = sv->lengths;
        for (size_t j = 0; j < sv->count; j++)
        {
            printf("%zu %s %d\n",j,*cptr,*i);
            cptr++;
            i++;
        }
    
        free(sv->splitted);
        free(sv->lengths);
        return 0;
    }
    

    还有我的 Go 文件:

    package main
    
    /*
    
    struct splitvalues {
        char** splitted;
        int* lengths;
        int count;
    };
    
    */
    import "C"
    
    import (
        "strings"
        "unsafe"
    )
    
    //export Split
    func Split(original *C.char, split *C.char) *C.struct_splitvalues {
        inputstring := C.GoString(original)
        splitstring := C.GoString(split)
        goResult := strings.Split(inputstring, splitstring)
        size := len(goResult)
    
        cLenghtsInt := C.malloc(C.size_t(size) * C.size_t(unsafe.Sizeof(C.int(0))))
        cSplittedStrings := C.malloc(C.size_t(size) * C.size_t(unsafe.Sizeof(uintptr(0))))
        returnStruct := (*C.struct_splitvalues)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_splitvalues{}))))
    
        ints := (*[1<<30 - 1]C.int)(cLenghtsInt)[:size:size]
        a := (*[1<<30 - 1]*C.char)(cSplittedStrings)
    
        for i, v := range goResult {
            ints[i] = C.int(len(v))
        }
    
        for idx, substring := range goResult {
            a[idx] = C.CString(substring)
        }
    
        returnStruct.splitted = (**C.char)(cSplittedStrings)
        returnStruct.lengths = (*C.int)(cLenghtsInt)
        returnStruct.count = C.int(len(goResult))
    
        return returnStruct
    }
    func main() {}
    

    输出是

    3
    0 hello 5
    1 nice 4
    2 world 5
    

    正如预期的那样。

    我不能保证这是最好的方法并且没有错误,所以不要以此作为参考。

    【讨论】:

      猜你喜欢
      • 2014-11-19
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      相关资源
      最近更新 更多