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))}