如何将指针切片传递给C函数 [英] How to pass pointer to slice to C function in go

查看:162
本文介绍了如何将指针切片传递给C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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

  / * 
#include
int f(int * c,char ** str){
int i;
printf(%d \\\
,* c);
for(i = 0; i <* c; i ++){
printf(%s\,str [i]);
}
* c =(* c)+ 1;
返回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:=范围strs {
c_strs [index] = C.CString(value)
defer C.free(unsafe.Pointer(c_strs [index]))
}

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

正如你所看到的,C函数当前是 int f(int * c,char ** str),但我想要的是 int f(int * c,char *** str)



这就是说:我实际上想要在C中启用对字符串数组(例如resize)的修改,并将其返回到Go字符串切片,以便我仍然可以在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) )))

//将C数组转换为一个Go Array,这样我们就可以对它进行索引
a:=(* [1 <= 30-1] * C.char)(cArray )
for index,value:= range strs {
a [index] = C.CString(value)
}

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


Background: using cgo to call C functions from Golang.

I want to use a C function which has this signature: int f(int *count, char ***strs). It will modify the data of count and strs, which is the reason why it uses pointer to them. The value of count is the length of strs; strs is an array of string; the return value is simply an (boolean) indicator which states whether there is an error or not.

In golang, I can successfully pass and modify count by using C.f((*C.int)(&count)); pass []string by using []*C.char. Sample code is like this:

/*
#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)
}

As you can see, the C function is currently int f(int *c, char **str), but what I'd like is int f(int *c, char ***str).

This is to say: what I actually want is to enable the modification to the string array (e.g. resize) in C and turn it back to a Go string slice so I can still use it in Go.

How to do this? I've searched and experimented for a while but with no luck.

解决方案

A Go slice is both allocated in Go, and a different data structure than a C array, so you can't pass it to a C function (cgo will also prevent you from doing this because a slice contains a Go pointer)

You need to allocate the array in C in order to manipulate the array in C. Just like with C.CString, you will also need to track where to free the outer array, especially if the C function may possibly allocate a new array.

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函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆