在Golang中使用C语言代码实例
cgo 使得在 golang 中可以使用 c 代码。
hello world
为了有一个较为直观的了解,我们来看一个简单的例子,创建文件 main.go:
package main
/*
#include <stdio.h>
void sayhi() {
printf("hi");
}
*/
import "c"
func main() {
c.sayhi()
}
执行程序:
go run main.go
程序执行并输出 hi(更多的范例可以见 $goroot/misc/cgo)。
windows 下的准备工作
如果想要在 windows 上使用 cgo,那么需要安装 gcc 编译器,这里我使用 mingw-w64。
设置编译和链接标志
我们使用 import “c” 导入的是一个伪包(pseudo-package),我们通过其来使用 c 代码。在 import “c” 之前,紧跟着 import “c” 的注释可以包括:
1.编译器和链接器标志
2.c 代码
我们可以通过 #cgo 指令来设置编译器和链接器标志,例如:
// #cgo cflags: -dpng_debug=1
// #cgo amd64 386 cflags: -dx86=1
// #cgo ldflags: -lpng
// #include <png.h>
import "c"
附带提及一点的是,这些指令中可以包含构建约束(build constraint),详细内容见: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 工具获取编译器和链接器标志(例如:#cgo pkg-config: png cairo)
golang 引用 c
结构体上需要注意的点:
1.c 结构体的域名称如果为 golang 的关键字时,访问时需要在域名称前面加上 _。比如说,c 中有一个结构体变量 x,此变量对应的结构体中有一个域 type,那么在 golang 中需要通过 x._type 来访问 type 域
2.结构体的位域、非对齐数据等无法在 golang 中表示时会被忽略
3.golang 结构体中不能使用 c 类型的域
标准的 c 数值类型对应:
1.c.char
2.c.schar(signed char)
3.c.uchar(unsigned char)
4.c.short
5.c.ushort(unsigned short)
6.c.int
7.c.uint(unsigned int)
8.c.long
9.c.ulong(unsigned long)
10.c.longlong(long long)
11.c.ulonglong(unsigned long long)
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 来释放内存
func c.cstring(string) *c.char
// 转换 c 字符串到 golang 字符串
func c.gostring(*c.char) string
// 转换一定长度的 c 字符串到 golang 字符串
func c.gostringn(*c.char, c.int) string
// 转换一块 c 内存区域到 golang 的字节数组中去
func c.gobytes(unsafe.pointer, c.int) []byte
其他需要注意的点:
1.c 语言中的 void* 对应 unsafe.pointer
2.c 语言中的结构、联合、枚举类型(而非变量),在 golang 中需要加上 struct_、union_、enum_ 前缀访问。由于 golang 中没有联合这种数据类型,因此 c 的联合在 golang 中被表示为字节数组
3.和 c 语言等价的那些类型是不可以导出的
推荐阅读
-
Spinner在Dialog中的使用效果实例代码详解
-
一起talk C栗子吧(第一百八十四回:C语言实例--在printf函数中设置输出宽度三)
-
再编写代码中报错:CS8107 C# 7.0 中不支持功能“xxxxxx”。请使用 7.1 或更高的语言版本。
-
C语言使用libcurl与json-c方法(代码实例)
-
在Golang中使用C语言代码实例
-
在angular 6中使用 less 的实例代码
-
C++ Part8 MFC中的AfxBeginThread的使用方法(代码实例)
-
使用C语言实例描述程序中的内聚和耦合问题
-
C语言二进制中1的个数(代码实例)
-
使用C语言访问51单片机中存储器的核心代码