2016-06-25 18 views
2

我正試圖與Go的一些C代碼接口。使用cgo,直到我遇到這種情況時(相當常見),這是相對直截了當的:需要將指針傳遞給本身包含指向某些數據的指針的結構。我似乎無法弄清楚如何從Go中做到這一點,而不是將結構的創建放入C代碼本身,我不希望這樣做。這裏是一個說明該問題的片段:如何在Go中填寫void * C指針?

package main 

// typedef struct { 
//  int size; 
//  void *data; 
// } info; 
// 
// void test(info *infoPtr) { 
//  // Do something here... 
// } 
import "C" 

import "unsafe" 

func main() { 
    var data uint8 = 5 
    info := &C.info{size: C.int(unsafe.Sizeof(data)), data: unsafe.Pointer(&data)} 
    C.test(info) 
} 

這枚編譯罰款,試圖運行它導致:

panic: runtime error: cgo argument has Go pointer to Go pointer 

在我的情況下,數據被傳遞給C調用不堅持過去的呼籲(即所討論的C代碼挖掘到結構,複製它需要的東西,然後返回)。

回答

2

看看cgo文檔"Passing pointers"部分:

Go代碼可以傳遞轉到指針至C提供轉到存儲器它指向不包含任何轉到指針。

而且也:

這些規則在運行時動態檢查。檢查由GODEBUG環境變量的cgocheck設置控制。默認設置是GODEBUG = cgocheck = 1,它執行合理便宜的動態檢查。這些檢查可能完全禁用,使用GODEBUG = cgocheck = 0。通過GODEBUG = cgocheck = 2可以完成對指針處理的完整檢查,但運行時會花費一些代價。

如果你運行你已經具備片段:

GODEBUG=cgocheck=0 go run snippet.go 

那就沒有恐慌。然而,走正確的方法是使用C.malloc(或獲得「C指針」從別的地方):

package main 

// #include <stdlib.h> 
// typedef struct { 
//  int size; 
//  void *data; 
// } info; 
// 
// void test(info *infoPtr) { 
//  // Do something here... 
// } 
import "C" 

import "unsafe" 

func main() { 
    var data uint8 = 5 

    cdata := C.malloc(C.size_t(unsafe.Sizeof(data))) 
    *(*C.char)(cdata) = C.char(data) 
    defer C.free(cdata) 

    info := &C.info{size: C.int(unsafe.Sizeof(data)), data: cdata} 
    C.test(info) 
} 

它的工作原理,因爲同時要定期去指針是不允許的,C.malloc返回一個「C指針」:

轉到指針裝置的指針由轉到所分配的存儲器(例如,通過使用&操作者或呼叫預定的新功能)和項C的指針裝置的指針被C分配的內存(例如,通過呼叫到C.malloc)。一個指針是一個Go指針還是一個C指針是一個由分配內存的方式決定的動態屬性。

請注意,您需要包含stdlib.h才能使用C.free

+1

謝謝。這就是我最終的結局......我只是希望稍微詳細一點。 –