2013-02-12 19 views
4

我想從一個go [] []字節轉換爲C **字符。換句話說,我有一個字節矩陣,我想將其轉換爲C中的字符雙指針。如何從[] []字節轉換爲** char in go

請假設我必須有一個[] []字節作爲輸入,並且** char作爲輸出。

我知道這是可以從[]字節轉換爲*通過執行類似字符:但似乎

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

它並不可能這種情況下延伸到第二維。我嘗試了一些相當精巧的東西,在這裏我將[] []字節裝入新的[]字節。然後我將這個[]字節發送到一個C函數,該函數使用指針運算創建一個** char,以指向正確位置的新[]字節。

雖然這種轉換給了我奇怪的行爲,但我的數據在幾次迭代中都是正確的,但在函數調用之間看起來會被破壞。

如果有人有任何想法,我會非常感激。

從答覆中我看到,說明我正在處理原始數據而不是字符串也很重要。因此,去字節類型。因此,如果添加C字符串結束符,原始數據將被破壞。我只是使用C ** char,因爲char是一個字節的大小。這就是說,謝謝你的迴應。我能夠根據我的需要調整已接受的答案。

回答

2

這必須手動完成。您必須分配一個新的**C.char類型並循環切入[][]byte切片中的每個元素,以將其分配給新列表。這涉及用每個迭代的正確大小來抵消**C.char指針。

這是一個示例程序,它執行此操作。

正如以下注釋所示,如果您打算在C中使用諸如printf之類的東西打印char *列表,請確保輸入字符串以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 
+1

我不認爲你已經終止了C字符串你有嗎?你的例子工作,但我懷疑你很幸運! – 2013-02-12 20:02:17

+0

完全正確。行*元素=(* C.char)(unsafe.Pointer(&list [i] [0]))'理想地應該讀取'* element = C.CString(string(list [i]))' – jimt 2013-02-13 00:49:20

+0

等待,爲什麼C結構必須以空結束?請不要以爲我正在使用字符串。我正在處理原始數據緩衝區。字符串函數是否仍然必須使用? – 2013-02-13 06:39:55

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) [email protected]:~/src/tmp/SO/14833531$ go run main.go 
"Hello" 
"world" 
(15:25) [email protected]:~/src/tmp/SO/14833531$ 
+0

什麼是你的榜樣嗎?你能說一點,除了你的代碼嗎? – Kissaki 2013-02-16 15:09:34

+0

該示例將Go [] []字節轉換爲空字符結尾的C **字符,然後將其打印在C端。這是你問的嗎?如果沒有,請詳細說明你的問題。 – zzzz 2013-02-16 15:29:34