cgo的效率 golang_golang CGO FAQ TIPS : cgo 从 C 传递 slice 到 go
cgo 從 C 傳遞 slice 到 go
這里一般會用在c的callback中。
需要加一個wrapper,比直接調用go函數中間多了一個轉換步驟,但方便了許多。
執行流程為,c調用發起 -> c wrapper -> go export
.go:
//export a_function_callback
func a_function_callback(args []C.astruct) {}
.c:
extern void a_function_callback(GoSlice args);
void a_function_callback_c(args *C.astruct) {
GoSlice args_go;
args_go.data = args;
args_go.len = nargs;
args_go.cap = nargs;
return a_function_callback(args_go);
}
這里的GoSlice需要從 export 出來的 .h 中獲取,或者 include 該 .h文件。
也可以直接拷貝過來,注意不要產生類型沖突。
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef long long GoInt64;
typedef GoInt64 GoInt;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
C.CString 的自動化回收方法
一般使用 C.CString 時,定義一個臨時變量存儲結果,使用 defer C.free 回收這個臨時的變量。
在 go 的 runtime 包中,有一個SetFinalizer方法,可以在回收對象的時候調用一個處理函數。
那么我們可以考慮使用它來自動化回收 C.CString產生的臨時變量。
type CString struct {
Ptr *C.char
}
func CCString(s string) *CString {
p := C.CString(s)
this := &CString{Ptr: p}
runtime.SetFinalizer(this, freeCString)
return this
}
func freeCString(cs *CString) {
C.free(unsafe.Pointer(cs.Ptr))
}
在使用的時候,基本能嵌入到調用的位置,不需要顯式定義一個臨時變量并執行 defer C.free。
C.somefunc(CCString(s).Ptr)
注意,只在somefunc不接管傳遞的參數的所有權時調用這種方式,如果somefunc接管了所有權,
而在未來某時間內存被回收了,則會出現程序SEGFAULT崩潰。
這種可能會產生一點runtime效率損失,另外還有額外的內存分配,看情況使用。
bool 類型的轉換處理
在 C 語言中,c99之前 bool 都是定義為 int的,要想轉換為go的bool類型,比較曲折。
var bval_c C.GBoolean
var bval_go bool
if int(bval) == 1 {
bval_go = true
} else {
bval_go = false
}
如果go有三元運算符的話,也可一行代碼實現該轉換,問題是go沒有三元運算符。
一般來說,對其包裝一個簡單的轉換函數比較好,比如 c2gobool(C.GBoolean).
有時候不同的 C 項目中 bool 定義不同,所以一般需要為每個項目定義這么一個函數,而不能放在一個庫中共用。
在 c99 之后,則沒有這個問題,cgo能夠直接判斷是內置的bool類型,能夠直接轉換為go的bool。
var bval_c C._Bool
var bval_go = bool(bval_c)
總結
以上是生活随笔為你收集整理的cgo的效率 golang_golang CGO FAQ TIPS : cgo 从 C 传递 slice 到 go的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python多进程队列中的队列_pyth
- 下一篇: linux中央服务器,如何在Linux上