简体   繁体   English

在C中使用Go slice

[英]Use Go slice in C

I'm trying to build a go shared library with a function that returns a slice. 我正在尝试使用返回切片的函数构建go共享库。
How can I use the slice from C code ? 如何使用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

I now have a lib.so and a lib.h 我现在有一个lib.so和一个lib.h

What would be the C code to print the values of the array ? 打印数组值的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

Use Go slice in C 在C中使用Go slice


Here's an example of C printing a Go byte slice: 这是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)
}

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 . func Test() []T的C返回值错误。返回长度和数组指针,例如cbuf

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. 首先,C不了解Go slice类型,也不知道如何操作它,因此您应该像在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. 您也无法在Go中分配切片,然后返回指向已分配内存的指针,而无需采取任何措施防止其被GC处理。 In this example it's probably simpler to just allocate the array in C. 在此示例中,仅使用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. 不要忘记,由于您是在C中分配内存,因此您还要负责释放它。 This goes for both the malloc call, as well as for the C.CString arrays. 这既适用于malloc调用,也适用于C.CString数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM