问题
I'm trying to build a go shared library with a function that returns a slice.
How can I use the slice from C code ?
package main
import "C"
type T struct {
A C.int
B *C.char
}
//export Test
func Test() []T {
arr := make([]T, 0)
arr = append(arr, T{C.int(1), C.CString("a")})
arr = append(arr, T{C.int(2), C.CString("abc")})
return arr
}
func main() {}
go build -o lib.so -buildmode=c-shared main.go
I now have a lib.so
and a lib.h
What would be the C code to print the values of the array ?
#include <stdio.h>
#include "lib.h"
typedef struct {
int A;
char* B;
} T;
int main() {
GoSlice a = Test();
for (int i = 0; i < 2; i++){
printf("%s\n", ((T *)a.data)[i].B);
}
}
gcc -o main main.c ./lib.so
回答1:
To start, C doesn't know about the Go slice type, nor how to manipulate it, so you should return an array pointer just like you would in C.
You also can't allocate the slice in Go then return a pointer to the allocated memory without some way to keep it from being GC'ed. In this example it's probably simpler to just allocate the array in C.
p := C.malloc(C.size_t(2))
// make a slice for convenient indexing
arr := (*[1 << 30]*T)(p)[:2:2]
arr[0] = &T{C.int(1), C.CString("a")}
arr[1] = &T{C.int(2), C.CString("abc")}
return p
You will also of course need to handle the array size, which you could do with by combining it into a struct like you did for strings, or accept a second pointer parameter to set to the return size.
Don't forget that since you are allocating the memory in C, you are also responsible for freeing it. This goes for both the malloc
call, as well as for the C.CString
arrays.
回答2:
Use Go slice in C
Here's an example of C printing a Go byte
slice:
package main
/*
#include <stdio.h>
void printbuf(size_t len, unsigned char *buf) {
printf("%lu [", len);
if (!buf) {
len = 0;
}
size_t maxwidth = 16;
size_t width = len <= maxwidth ? len : maxwidth;
for (size_t i = 0; i < width; i++) {
if (i > 0) {
printf(" ");
}
printf("%02X", buf[i]);
}
if (width < len) {
printf(" ...");
}
printf("]\n");
}
*/
import "C"
func cbuf(buf []byte) (size C.size_t, ptr *C.uchar) {
var bufptr *byte
if cap(buf) > 0 {
bufptr = &(buf[:1][0])
}
return C.size_t(len(buf)), (*C.uchar)(bufptr)
}
func main() {
buf := make([]byte, 24, 32)
for i := range buf {
buf[i] = byte(i)
}
bufsize, bufptr := cbuf(buf)
C.printbuf(bufsize, bufptr)
}
Output:
24 [00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...]
func Test() []T
has the wrong return values for C. Return a length and an array pointer, like cbuf
.
来源:https://stackoverflow.com/questions/51525876/use-go-slice-in-c