【问题标题】:convert array of strings from CGO in GO在 GO 中从 CGO 转换字符串数组
【发布时间】:2020-09-12 15:52:45
【问题描述】:

我可以转换从 Go 中的 C (cgo) 函数返回的字符串数组 (char**) 吗? 下面的代码编译并运行,但我无法通过字符串列表进行范围。
而且我什至不确定它是否违反了“传递指针”的规则:https://golang.org/cmd/cgo/ 任何想法都会有所帮助,自从我用 C 编码以来已经有好几年了!提前致谢!

package main
/*
#include "stdlib.h"

char** getlist ()
{
    char **array = NULL;
    array = (char**)realloc(array, 2*sizeof(*array));
    array[0]="HELLO";
    array[1]="WORLD";
    return array;
}

*/
import "C"

import (
    "log"
    "unsafe"
)

func main() {
    list := C.getlist();
    log.Printf("\n========\n C.getList()=%s", list)
    ulist := unsafe.Pointer(list)
    log.Printf("\n========\nulist=%s", ulist)
}

【问题讨论】:

  • 参见 cgo 上的 wiki 页面,例如:github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
  • 感谢您的评论,但 wiki 页面的示例是针对一维数组的。我将如何为二维数组编写转换代码?我返回的是 C.char** 而不是 C.char*。
  • 外部数组仍然是“1D”,内部类型没有改变任何东西。我举个例子

标签: pointers go cgo


【解决方案1】:

为了在 Go 中迭代字符串,您需要将数组转换为 Go 切片。我们可以在这里跳过分配,直接进行转换(您的示例将长度静态设置为 2,但实际上您可能有另一个来源)

cSlice := (*[1 << 28]*C.char)(unsafe.Pointer(list))[:2:2]

我们可以直接对其进行迭代,并使用C.GoString 函数来转换C 字符串。这样存储起来更安全,因为它将数据复制到 Go 内存中,但是如果这个切片非常大,我们可以使用与上述相同的不安全转换来保存分配,尽管您首先需要找到每个字符串的长度。

var slice []string
for _, s := range (*[1 << 28]*C.char)(unsafe.Pointer(list))[:2:2] {
    slice = append(slice, C.GoString(s))
}

【讨论】:

  • 太棒了-谢谢!有什么办法可以得到数组的长度吗?我将 2 更改为更大的数字,如果我在 s 上检查 nil 并中断循环: if s == nil { break } 我可以得到长度,因为第三个元素是 nil,但我注意到第四个元素不是 nil .我基本上是通过循环一个切片来践踏未知的内存位置:(unsafe.Pointer(list))[:2000:2000]?
  • @user3757849:您要么需要获取带外的数组大小(大多数 C 函数将返回数组的大小以及数组本身),要么您需要知道最终的标记是什么value 是要查找的,在 C 字符串的情况下为 null。不幸的是,有办法避免需要知道 C 如何使用 cgo。您可以检查nil,只要您可以确定为最终数组元素分配了一个额外的空值。
  • 你好,谢谢。是的,最后保留一个空值是个好主意。我明白你关于理解 C 的观点!我可能会变得勇敢并尝试通过指针返回数组的长度。 C 慢慢地开始回到我身边。
猜你喜欢
  • 2023-02-24
  • 2014-10-09
  • 1970-01-01
  • 2021-08-29
  • 2017-05-20
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
相关资源
最近更新 更多