【问题标题】:How to pass pointer to slice to C function in go如何在go中将指向切片的指针传递给C函数
【发布时间】:2017-06-28 19:38:43
【问题描述】:

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

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

在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, char ***str)

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

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

【问题讨论】:

  • 您确定在主程序中分配的内存可以在C函数中重新分配吗?这可能是内存管理的差异
  • 让函数返回一个char**,而不是诉诸三星级编程。该函数的返回码目前没有任何意义。
  • @VolAnd 当前工作部分(char**)是正确的。但是,我不确定要为我的目标做什么 (char***)。
  • @Lundin 这只是一个示例......不是我的实际代码所做的

标签: c go cgo


【解决方案1】:

Go 切片在 Go 中分配,并且数据结构与 C 数组不同,因此您不能将其传递给 C 函数(cgo 也会阻止您这样做,因为切片包含 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)))

【讨论】:

  • 我仍在尝试如何从a 正确获取 go 字符串 - 仅使用 C.GoString(a[0]) 不会产生正确的结果。但是……神奇的数字 30 有什么作用?
  • @renyuneyun:“幻数”不是 30,而是 1&lt;&lt;30-1,或者 1073741823。这只是一个很大的数组,因为数组类型是静态的。
  • 非常感谢 :) (是的,我知道这是按位运算。)我只是碰巧看到了这个值,我想知道为什么它是 2^30 而不是其他值。关于获取 go 字符串,再次分配 a 以获取 cArray 的新指针值会产生成功的结果。
  • @renyuneyun:好吧,在这种情况下,30 是因为2^30 - 1 是可用于所有架构的最大数组大小。
猜你喜欢
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2021-11-02
  • 1970-01-01
  • 2013-04-28
相关资源
最近更新 更多