如何从 CGO 返回结构
Posted
技术标签:
【中文标题】如何从 CGO 返回结构【英文标题】:How to return struct from CGO 【发布时间】:2020-10-28 14:23:13 【问题描述】:我想从 C 中调用一个返回结构的 Go 函数,并且在 C 中我想处理该结构。
目标是用数据填充结构并返回信息。我不知道哪种格式最好通过。我需要在 C 代码中获取有关返回数据长度的信息,以及结构的每个 str
和 l
值。
(我调用的函数不是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, retvaluestr: 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
【问题讨论】:
【参考方案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
正如预期的那样。
我不能保证这是最好的方法并且没有错误,所以不要以此作为参考。
【讨论】:
以上是关于如何从 CGO 返回结构的主要内容,如果未能解决你的问题,请参考以下文章