c - 如何在go中将指向 slice 的指针传递给C函数

标签 c go cgo

背景:使用cgo从Golang中调用C函数。

我想使用具有此签名的 C 函数:int f(int *count, char ***strs)。 它会修改countstrs的数据,这就是它使用指针指向它们的原因。 count的值为strs的长度; strs是一个字符串数组;返回值只是一个( bool 值)指示器,指示是否存在错误。

在golang中,我可以通过使用C.f((*C.int)(&count))成功传递和修改count;使用 []*C.char 传递 []string。示例代码如下:

/*
#include <stdio.h>
int f(int *c, char **str) {
    int i;
    printf("%d\n", *c);
    for (i = 0; i < *c; i++) {
        printf("%s\n", str[i]);
    }
    *c = (*c) + 1;
    return 1;
}
*/
import "C"
func go_f(strs []string) int {
    count := len(strs)
    c_count := C.int(count)

    c_strs := make([]*C.char, count)
    for index, value := range strs {
        c_strs[index] = C.CString(value)
        defer C.free(unsafe.Pointer(c_strs[index]))
    }

    err := C.f(&c_argc, (**C.char)(&c_argv[0]))
    return int(err)
}

如您所见,C 函数当前是 int f(int *c, char **str),但我想要的是 int f(int *c,字符 ***str).

这就是说:我真正想要的是在 C 中启用对字符串数组的修改(例如调整大小)并将其转回 Go 字符串 slice ,这样我仍然可以在 Go 中使用它。

如何做到这一点?我已经搜索和试验了一段时间,但没有成功。

最佳答案

Go slice 是在 Go 中分配的,并且是与 C 数组不同的数据结构,所以你不能将它传递给 C 函数(cgo 也会阻止你这样做,因为 slice 包含一个 Go 指针)

您需要在 C 中分配数组以便在 C 中操作数组。就像使用 C.CString 一样,您还需要跟踪释放外部数组的位置,特别是如果 C 函数可能分配一个新的大批。

cArray := C.malloc(C.size_t(c_count) * C.size_t(unsafe.Sizeof(uintptr(0))))

// convert the C array to a Go Array so we can index it
a := (*[1<<30 - 1]*C.char)(cArray)
for index, value := range strs {
    a[index] = C.CString(value)
}

err := C.f(&c_count, (***C.char)(unsafe.Pointer(&cArray)))

关于c - 如何在go中将指向 slice 的指针传递给C函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42530538/

相关文章:

go - 我可以在生产中使用 master libpq 吗

go - ASN.1 Unmarshalling using go structs 给出标签不匹配错误

go - 在 Go 中连接到多个数据库的好习惯是什么?

c - 将字符串文字传递给 C

c - char *a[]= {"hello", "world"}; 之间有什么区别?和 char a[][10]= {"hello", "world"};?

c - 在不改变输入的情况下实现 strcat

go - int 和 C.int 之间有什么区别?

go - CGO如何将 slice 传递给Rust

c - memcpy 在 Linux 中移动 128 位

c - 为什么我的 for 循环不接受 9 个输入?