在Golang中使用C语言代码实例
cgo使得在Golang中可以使用C代码。
HelloWorld
为了有一个较为直观的了解,我们来看一个简单的例子,创建文件main.go:
packagemain /* #include<stdio.h> voidsayHi(){ printf("Hi"); } */ import"C" funcmain(){ C.sayHi() }
执行程序:
gorunmain.go
程序执行并输出hi(更多的范例可以见$GOROOT/misc/cgo)。
Windows下的准备工作
如果想要在Windows上使用cgo,那么需要安装gcc编译器,这里我使用mingw-w64。
设置编译和链接标志
我们使用import“C”导入的是一个伪包(pseudo-package),我们通过其来使用C代码。在import“C”之前,紧跟着import“C”的注释可以包括:
1.编译器和链接器标志
2.C代码
我们可以通过#cgo指令来设置编译器和链接器标志,例如:
//#cgoCFLAGS:-DPNG_DEBUG=1 //#cgoamd64386CFLAGS:-DX86=1 //#cgoLDFLAGS:-lpng //#include<png.h> import"C"
附带提及一点的是,这些指令中可以包含构建约束(buildconstraint),详细内容见:http://golang.org/pkg/go/build/#hdr-Build_Constraints。
常用的#cgo指令有:
1.CPPFLAGS、CFLAGS指令被用于编译当前包中的C文件(任何的.c、.s、.S文件)
2.CPPFLAGS、CXXFLAGS指令被用于编译当前包中的C++文件(任何的.cpp、.cc、.cxx文件)
3.LDFLAGS指令用于指定链接器标志
4.pkg-config指令用于通过pkg-config工具获取编译器和链接器标志(例如:#cgopkg-config:pngcairo)
Golang引用C
结构体上需要注意的点:
1.C结构体的域名称如果为Golang的关键字时,访问时需要在域名称前面加上_。比如说,C中有一个结构体变量x,此变量对应的结构体中有一个域type,那么在Golang中需要通过x._type来访问type域
2.结构体的位域、非对齐数据等无法在Golang中表示时会被忽略
3.Golang结构体中不能使用C类型的域
标准的C数值类型对应:
1.C.char
2.C.schar(signedchar)
3.C.uchar(unsignedchar)
4.C.short
5.C.ushort(unsignedshort)
6.C.int
7.C.uint(unsignedint)
8.C.long
9.C.ulong(unsignedlong)
10.C.longlong(longlong)
11.C.ulonglong(unsignedlonglong)
12.C.float
13.C.double
任何的C函数(包括void函数)都可以返回一个返回值和C的errno变量(作为错误):
n,err:=C.sqrt(-1) _,err:=C.voidFunc()
直接调用C函数指针目前还无法支持。
有一些特殊的函数可以用于C类型和Golang类型之间转换(通过数据拷贝的方式),伪定义如下:
//Golang的字符串转为C字符串 //C的字符串是使用malloc分配的,因此,此函数的调用者 //需要调用C.free来释放内存 funcC.CString(string)*C.char //转换C字符串到Golang字符串 funcC.GoString(*C.char)string //转换一定长度的C字符串到Golang字符串 funcC.GoStringN(*C.char,C.int)string //转换一块C内存区域到Golang的字节数组中去 funcC.GoBytes(unsafe.Pointer,C.int)[]byte
其他需要注意的点:
1.C语言中的void*对应unsafe.Pointer
2.C语言中的结构、联合、枚举类型(而非变量),在Golang中需要加上struct_、union_、enum_前缀访问。由于Golang中没有联合这种数据类型,因此C的联合在Golang中被表示为字节数组
3.和C语言等价的那些类型是不可以导出的