#struct #shared-libraries #cgo
#struct #разделяемые библиотеки #cgo
Вопрос:
Я хотел бы вызвать функцию Go из C, которая возвращает struct, и в C я хотел бы поработать над struct .
Цель состоит в том, чтобы заполнить структуру данными и вернуть информацию. Я не знаю, какой формат лучше всего передать. Мне нужно получить информацию в коде C о длине возвращаемых данных, а также о каждом str
и l
значении структуры.
(Функция, которую я вызываю, не strings.Split())
является . Это что-то более сложное, но мне нужны возвращаемые значения a char*
и an 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("%#vn", 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("%dn",sv->count);
char** cptr = sv->splitted;
int *i = sv->lengths;
for (size_t j = 0; j < sv->count; j )
{
printf("%zu %s %dn",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
как и ожидалось.
Я не могу обещать, что это лучший способ и что ошибок нет, поэтому не принимайте это как ссылку.