Jump to Navigation

cgo封装C库总结

简介

cgo是go语言提供的一种与C语言相互调用的方式。

cgo能够让开发者直接在.go源代码文件中嵌入C代码。

在嵌入的C代码比较长的时候,还允许在分离.c文件中编写C代码。

cgo的基本处理机制是,根据特定格式的cgo指令,解析出C源代码和编译参数,

调用gcc编译并把结构合并到最终二进制程序中。

带来的问题,编译速度慢了很多。 两种模型,

cgo用法:

声明使用cgo

在.go文件中,插入这么几行,表示开启cgo功能:

/*

*/

import "C"

其实这并不是一个简单的开关,而是特定的语法序列标识,当go解析器遇到该语法序列时,

自动进入cgo模式,处理与cgo有关的功能。

注意,这个注释确实是注释,并没有写错。在这个注释段能够添加C源代码。

一般把这个块叫做“C语言嵌入注释块”。

还有一个需要注意的是在注释结尾处,要紧跟着import "C"语句,否则这块注释会被当作注释忽略了。

声明cgo编译参数

cgo的编译参数,也就是cgo调用gcc的用到的编译参数,用来支持gcc编译过程中查找头文件,库,标识等。 常用的参数有,CFLAGS,LDFLAGS。

这里用到了#cgo指令了,关于指令,指的是一种特殊语法序列,告诉编译器做特定的处理。

而cgo的编译参数则必须出现在C语言嵌入注释块中,可以多次出现。如:

/*

#cgo CFLAGS: -g -O2

#cgo LDFLAGS: -L/path/to/3rdlib/

*/

import "C"

在.go中编写简单的C代码
/*
#cgo CFLAGS: -g -O2
#cgo LDFLAGS: -L/path/to/3rdlib/
#include <stdlib.h>
void hello() {
    printf("hello cgo\n");
}
*/
import "C"

func Hello() {
    C.hello()
}

cgo FAQ

不能在go struct中嵌入C.xxx,只能嵌入*C.xxx,即不能嵌入C结构体值,能嵌入C结构体指针。

字符串转换,C.CString <=> C.GoString 注意,由C.CString生成的指针,需要使用defer C.free(unsafe.Pointer(p))释放。

整数转换, 强制类型转换式操作,如n := int32(C.int32_t),即可转换成go类型的整数。

整数转换, 强制类型转换式操作,如n := C.int32_t(int32),即可转换成C类型的整数。

字符串指针转换,C.CString()的C.char <=> *C.uchar <=> *C.uint8_t??? 这个可以使用一个简单的cgo函数实现。static uint8_t *char2uint8(char *s) { return (uint8_t)s; }

void*类型 <=> unsafe.Pointer。 这两个比较容易处理,在go语言中传入付出C时是完全等价的的类型。

在C中回调go的函数:注意,go函数的参数应该是C.xxx类型。 需要使用//export指令让go函数能在C中被访问。

go函数指针,如何传递到C中??? 这个比较复杂一些,在单独一节中给出更全面的解答。

一个unsafe.Pointer再怎么转换成实际的Go类型??? 使用强制转换语法,如(*YourType)(p)。

C语言函数指针的传递

假设有一个C函数的原型为 int fortytwo();

需要在go中把它当作函数指针传递给另一个C函数: int callback_fortytwo(int(*fn)());

由于go中无法直接拿到该函数指针,也无法理解函数指针类型int(*)(),需要做个转换处理,

在C语言嵌入注释块中,把函数指针:

typedef int (*callback_fn)();

编写一个使用这个typedef的封装C函数:

int callback_fortytwo_wrap(callback_fn fn) { return callback_fortytwo(fn); }

在go函数中,编写参数传递代码,

func gocallit() {
    var _cbfun = (C.callback_fn)(C.fortytwo)
    C.callback_fortytwo_wrap(_cbfun)
}

这样能够在go语言中获取C语言函数指针与类型,并实现C语言函数指针的传入与传出操作。

golang的注释指令:(分类://注释指令,#注释指令)

//export 在"//export"中间不能有空格,以下双斜线注释指令一样遵寻该规则。

//line

//go:noescape

//go:generate ***

#cgo

参考:

https://code.google.com/p/go-wiki/wiki/cgo

http://golang.org/cmd/cgo/

http://blog.golang.org/c-go-cgo

实践项目

https://github.com/kitech/go-toxcore

https://github.com/kitech/gearman-cgo

添加新评论

Plain text

  • 不允许HTML标记。
  • 自动将网址与电子邮件地址转变为链接。
  • 自动断行和分段。
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.


Main menu 2

Story | by Dr. Radut