在C中使用Go slice

时间:2018-07-25 18:54:35

标签: c go cgo

我正在尝试使用返回切片的函数构建go共享库。
如何使用C代码中的切片?

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

我现在有一个lib.so和一个lib.h

打印数组值的C代码是什么?

#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

2 个答案:

答案 0 :(得分:0)

  

在C语言中使用Go切片


以下是C打印Go byte切片的示例:

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)
}

输出:

24 [00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...]

func Test() []T的C返回值错误。返回长度和数组指针,例如cbuf

答案 1 :(得分:0)

首先,C不了解Go slice的类型,也不知道如何操作它,因此您应该像在C中一样返回数组指针。

您也不能在Go中分配切片,然后返回指向已分配内存的指针,而无需采取任何措施防止其被GC处理。在此示例中,仅使用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

当然,您还需要处理数组大小,可以通过将其组合到一个结构中来处理数组大小,就像处理字符串一样,或者接受第二个指针参数设置为返回大小。

不要忘记,由于您正在C中分配内存,因此您还负责释放它。这既适用于malloc调用,也适用于C.CString数组。