cgo的一些經驗

cgo能夠在go語言中夾雜着C函數或數據,在使用cgo時,有一些須要注意的:數組

一、go中的int/int32/int64/uint32/uint64和C語言中的int/int32等是不一樣的,所以,C語言的函數的參數不能是go語言的int,須要轉換,同理,go函數的int也不能使用C的int,須要轉換。函數

go int轉換爲C int的方法:ui

C.int(n)spa

還有一點,C的函數調用中,有不少參數是size_t類型,其實就是一個整型,但若是使用C.int()做爲C函數的參數,就會編譯出錯:指針

 cannot use _Ctype_int(100) (type C.int) as type C.size_t in function argument內存

go編譯器嚴格限制參數類型必須一致,所以必須是size_t類型的參數。這是由於go語言沒有C語言裏面的強制轉換的概念,你可使用文檔

C.size_t(n)來獲得C語言中的sizt_t類型。字符串

二、go語言中的字符串和C語言中的字符串轉換編譯器

C.Cstringstring

C.GoString

….

具體能夠參考文檔。

三、結構體

使用C.struct_xxxx

若是使用struct中的成員變量,能夠直接用.來訪問。

四、指針

使用unsafe.Pointer()來轉換,例如須要轉換爲 int *:

(*C.int)(unsafe.Pointer(&v))

在c語言中,指針即數組,可使用ptr[n]來得到指針的第n個偏移,但在go中,這樣不行,會報錯:

invalid operation:xxxx

go語言中,指針沒有這樣的操做。

須要使用unsafe.Pointer和uintptr配合來獲取指針的偏移。

五、函數調用

C.func()

文檔中說,go調用全部的C函數都會返回兩個值,後一個值爲error類型,即便是void函數。文檔表述以下:

n, err := C.sqrt(-1)
_, err := C.voidFunc()

但我發現,C.malloc彷佛只返回一個值。

六、C語言中的NULL在go中是nil

例如

s := C.malloc(C.sizeof(100))

if s == nil {

….

}

這個很重要,在沒發現nil能夠比較c的指針前,我是這樣比較的:

(*C.char)(unsafe.Pointer(uintptr(0)))

不過,cgo的文檔還很匱乏,不少都須要閱讀代碼。

package main

/*
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

struct t {
char *s;
};

*/
import 「C」

import 「unsafe」
import 「fmt」

func main() {
var t C.struct_t
var s = 「hello world」
var ch *C.char
var tmp *C.char

// 分配空間, 並判斷是否分配成功
t.s  = (*C.char)(C.malloc(C.size_t(100)))
if t.s == nil {
//if t.s == (*C.char)(unsafe.Pointer(uintptr(0))) {
panic(「malloc failed!\n」)
}

        // 釋放內存

        defer C.free(unsafe.Pointer(t.s))

// 將go的字符串轉爲c的字符串,並自動釋放
ch = C.CString(s)
defer C.free(unsafe.Pointer(ch))

       // 調用C的strncpy函數複製
C.strncpy(t.s, ch, C.size_t(len(s)))

// C的指針操做
for i := C.size_t(0); i < C.strlen(t.s); i ++ {
tmp = (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(t.s)) + uintptr(i)))
*tmp = C.char(C.toupper(C.int(*tmp)))
}

fmt.Printf(「%s\n」, C.GoString(t.s))

        fmt.Printf(「sizeof struct t is %v\n」, unsafe.Sizeof(t))}

相關文章
相關標籤/搜索