如何将Go字符串数组转换为C字符串数组?

huangapple go评论92阅读模式
英文:

How do I convert a Go array of strings to a C array of strings?

问题

我正在一个项目中使用cgo,并且想要导出一个函数供使用。以下是我想要实现的示例代码:

package csplit

import (
    "C"
    "strings"
)

//export Split
/* Split函数接受两个C字符串作为参数,第二个字符串表示要进行分割的子字符串,然后返回一个字符串数组。示例:
   Split("1,2", ",") // 返回["1", "2"]
*/
func Split(original *C.char, split *C.char) []*C.char {
    goResult := strings.Split(C.GoString(original), C.GoString(split))
    cResult := make([]*C.char, len(goResult))

    for idx, substring := range goResult {
        cResult[idx] = C.CString(substring)
    }

    return cResult
}

问题在于返回类型是Go分配的数据,而不是移动到C堆上。这会导致出现以下错误:runtime error: cgo result has Go pointer

英文:

I am using cgo in a project, and I want to export a function for use. Here's an example of what I want to achieve:

package csplit

import (
    "C"
    "strings"
)

//export Split
/* The Split function takes two C strings, the second of which represents
   a substring to split on, and returns an array of strings. Example:
       Split("1,2", ",") // gives ["1", "2"]
*/
func Split(original *C.char, split *C.char) []*C.char {
        goResult := strings.Split(C.GoString(original), C.GoString(split))
        cResult := make([]*C.char, len(goResult))

        for idx, substring := range goResult {
                cResult[idx] = C.CString(substring)
        }

        return cResult
}

The problem is that the return type is Go allocated data, and not moved into the C heap. This panics with: runtime error: cgo result has Go pointer

答案1

得分: 14

你正在返回一个在Go中分配的Go切片,它与C数组是不同的结构。你需要在C中分配一个数组:

//export Split
func Split(original *C.char, split *C.char) **C.char {
    goResult := strings.Split(C.GoString(original), C.GoString(split))
    cArray := C.malloc(C.size_t(len(goResult)) * C.size_t(unsafe.Sizeof(uintptr(0))))

    // 将C数组转换为Go数组,以便我们可以对其进行索引
    a := (*[1<<30 - 1]*C.char)(cArray)

    for idx, substring := range goResult {
        a[idx] = C.CString(substring)
    }

    return (**C.char)(cArray)
}
英文:

You're returning a Go slice which is allocated in Go, and is a different structure than a C array. You need to allocate an array in C:

//export Split
func Split(original *C.char, split *C.char) **C.char {
	goResult := strings.Split(C.GoString(original), C.GoString(split))
	cArray := C.malloc(C.size_t(len(goResult)) * C.size_t(unsafe.Sizeof(uintptr(0))))

	// convert the C array to a Go Array so we can index it
	a := (*[1&lt;&lt;30 - 1]*C.char)(cArray)

	for idx, substring := range goResult {
		a[idx] = C.CString(substring)
	}

	return (**C.char)(cArray)
}

huangapple
  • 本文由 发表于 2017年1月6日 02:24:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/41492071.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定