cgo可以在go语言中夹杂着C函数或数据,在使用cgo时,有一些需要注意的: 1、go中的int/int32/int64/uint32/uint64和C语言中的int/int32等是不同的,因此,C语言的函数的参数不能是go语言的int,需要转换,同理,go函数的int也不能使用C的int,需要转换。 C.int(n) 还有一点,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类型。 2、go语言中的字符串和C语言中的字符串转换 C.Cstring C.GoString …. 3、结构体 使用C.struct_xxxx 如果使用struct中的成员变量,可以直接用.来访问。 4、指针 使用unsafe.Pointer()来转换,例如需要转换为 int *: (*C.int)(unsafe.Pointer(&v)) 在c语言中,指针即数组,可以使用ptr[n]来获得指针的第n个偏移,但在go中,这样不行,会报错: invalid operation:xxxx go语言中,指针没有这样的操作。 需要使用unsafe.Pointer和uintptr配合来获取指针的偏移。 5、函数调用 C.func() 文档中说,go调用所有的C函数都会返回两个值,后一个值为error类型,即使是void函数。文档表述如下: n, err := C.sqrt(-1) _, err := C.voidFunc() 但我发现,C.malloc似乎只返回一个值。 6、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 #include #include 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)) }