5

我想从 go [][]byte 转换为 C **char。换句话说,我在 go 中有一个字节矩阵,我想在 C 中将其转换为 char 双指针。

请假设我必须有一个 [][]byte 作为输入和一个 **char 作为输出。

我知道可以通过执行以下操作将 []byte 转换为 *char:

((*C.char)(unsafe.Pointer(&data[0])))

但似乎不可能将这种情况扩展到第二维。我已经尝试了一些非常精细的方法,我将一个 [][]byte 打包到一个新的 []byte 中。然后我将该 []byte 发送到一个 C 函数,该函数使用指针算法创建一个 **char 以指向正确位置的新 []byte。

这种转换给了我奇怪的行为,我的数据在几次迭代中是正确的,但在函数调用之间似乎被破坏了。

如果有人有任何想法,我将不胜感激。

从我看到的回复中,声明我正在使用原始数据而不是字符串也很重要。因此是 go 字节类型。因此,如果添加 C 字符串终止符,原始数据将被破坏。我只是使用 C **char,因为 char 的大小是一个字节。也就是说,感谢您的回复。我能够根据自己的需要调整接受的答案。

4

2 回答 2

4

未经测试的骨架:

func foo(b [][]byte) {
        outer := make([]*C.char, len(b)+1)
        for i, inner := range b {
                outer[i] = C.CString(string(inner))
        }
        C.bar(unsafe.Pointer(&outer[0])) // void bar(**char) {...}
}

编辑:完整示例(经过测试):

package main

/*
#include <stdlib.h>
#include <stdio.h>

void bar(char **a) {
        char *s        ;
        for (;(s = *a++);)
                printf("\"%s\"\n", s);
}
*/
import "C"
import "unsafe"

func foo(b [][]byte) {
        outer := make([]*C.char, len(b)+1)
        for i, inner := range b {
                outer[i] = C.CString(string(inner))
        }
        C.bar((**C.char)(unsafe.Pointer(&outer[0]))) // void bar(**char) {...}
}

func main() {
        foo([][]byte{[]byte("Hello"), []byte("world")})
}

(15:24) jnml@fsc-r550:~/src/tmp/SO/14833531$ go run main.go 
"Hello"
"world"
(15:25) jnml@fsc-r550:~/src/tmp/SO/14833531$ 
于 2013-02-12T13:56:08.290 回答
3

这必须手动完成。您必须分配一个新**C.char类型并遍历[][]byte切片中的每个元素以将其分配给新列表。**C.char这涉及为每次迭代将指针偏移正确的大小。

这是一个执行此操作的示例程序。

正如下面的评论所暗示的,如果您打算char *使用类似 C 的东西打印列表printf,请确保输入字符串以 NULL 结尾。理想情况下,通过使用C.CString()函数转换它们。这假设它们将被视为字符串。否则,您可能还需要提供一种将每个单独char *列表的长度传递给 C 函数的方法。

package main

/*
#include <stdlib.h>
#include <stdio.h>

void test(char **list, size_t len)
{
    size_t i;

    for (i = 0; i < len; i++) {
        //printf("%ld: %s\n", i, list[i]);
    }
}
*/
import "C"
import "unsafe"

func main() {
    list := [][]byte{
        []byte("foo"),
        []byte("bar"),
        []byte("baz"),
    }

    test(list)
}

func test(list [][]byte) {
    // Determine the size of a pointer on the current system.
    var b *C.char
    ptrSize := unsafe.Sizeof(b)

    // Allocate the char** list.
    ptr := C.malloc(C.size_t(len(list)) * C.size_t(ptrSize))
    defer C.free(ptr)

    // Assign each byte slice to its appropriate offset.
    for i := 0; i < len(list); i++ {
        element := (**C.char)(unsafe.Pointer(uintptr(ptr) + uintptr(i)*ptrSize))
        *element = (*C.char)(unsafe.Pointer(&list[i][0]))
    }

    // Call our C function.
    C.test((**C.char)(ptr), C.size_t(len(list)))
}

输出如下:

$ go run charlist.go 
0: foo
1: bar
2: baz
于 2013-02-12T14:05:44.137 回答