参考文献列表:
[url]http://golang.org/cmd/cgo/[/url]
cgo 使得在 Golang 中可以使用 C 代码。
Hello World
为了有一个较为直观的了解,我们来看一个简单的例子,创建文件 main.go:
执行程序:
程序执行并输出 hi(更多的范例可以见 $GOROOT/misc/cgo)。我们可以使用命令:
来显示构建时的命令。
Windows 下的准备工作
如果想要在 Windows 上使用 cgo,那么需要安装 gcc 编译器,这里我使用 [url=http://sourceforge.net/projects/mingw-w64/]mingw-w64[/url],可以在[url=http://nuwen.net/mingw.html]这里[/url]、[url=http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/]这里[/url]下载,另外你也可以使用 [url=http://tdm-gcc.tdragon.net/]TDM-GCC[/url]。
设置编译和链接标志
我们使用 import “C” 导入的是一个伪包(pseudo-package),我们通过其来使用 C 代码。在 import “C” 之前,紧跟着 import “C” 的注释可以包括:
编译器和链接器标志
C 代码
我们可以通过 #cgo 指令来设置编译器和链接器标志,例如:
附带提及一点的是,这些指令中可以包含构建约束(build constraint),详细内容见:[url]http://golang.org/pkg/go/build/#hdr-Build_Constraints[/url]。
常用的 #cgo 指令有:
CPPFLAGS、CFLAGS 指令被用于编译当前包中的 C 文件(任何的 .c、.s、.S 文件)
CPPFLAGS、CXXFLAGS 指令被用于编译当前包中的 C++ 文件(任何的 .cpp、.cc、.cxx 文件)
LDFLAGS 指令用于指定链接器标志
pkg-config 指令用于通过 pkg-config 工具获取编译器和链接器标志(例如:#cgo pkg-config: png cairo)
在 Golang 的工具发现存在使用 import “C” 的 Golang 源文件时,它将会查找当前目录下的非 Golang 源文件并编译它们作为此 Golang 包的一部分:
文件 test.c
进行构建工作:
go build
需要注意的是,使用 go build test.go 将不会编译 test.c 文件。
Golang 引用 C
结构体上需要注意的点:
C 结构体的域名称如果为 Golang 的关键字时,访问时需要在域名称前面加上 _。比如说,C 中有一个结构体变量 x,此变量对应的结构体中有一个域 type,那么在 Golang 中需要通过 x._type 来访问 type 域
结构体的位域、非对齐数据等无法在 Golang 中表示时会被忽略
Golang 结构体中不能使用 C 类型的域
标准的 C 数值类型对应:
任何的 C 函数(包括 void 函数)都可以返回一个返回值和 C 的 errno 变量(作为错误):
直接调用 C 函数指针目前还无法支持。
有一些特殊的函数可以用于 C 类型和 Golang 类型之间转换(通过数据拷贝的方式),伪定义如下:
其他需要注意的点:
C 语言中的 void* 对应 unsafe.Pointer
C 语言中的结构、联合、枚举类型(而非变量),在 Golang 中需要加上 struct_、union_、enum_ 前缀访问。由于 Golang 中没有联合这种数据类型,因此 C 的联合在 Golang 中被表示为字节数组
和 C 语言等价的那些类型是不可以导出的
C 引用 Golang
Golang 的函数可以导出给 C 使用:
对应的 C 代码为(被生成在 _cgo_export.h 中):
有几点需要注意:
Golang 函数的多个返回值会被映射为一个 C 结构体
使用 //export 来使得 Golang 函数可以在 C 中引用。在使用了 //export 之后,此 Golang 源文件中就不能包含 C 的定义(但可以存在声明)
References:
[url]http://name5566.com/4934.html?utm_source=tuicool[/url]
[url]http://golang.org/cmd/cgo/[/url]
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)。我们可以使用命令:
go build -x main.go
来显示构建时的命令。
Windows 下的准备工作
如果想要在 Windows 上使用 cgo,那么需要安装 gcc 编译器,这里我使用 [url=http://sourceforge.net/projects/mingw-w64/]mingw-w64[/url],可以在[url=http://nuwen.net/mingw.html]这里[/url]、[url=http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/]这里[/url]下载,另外你也可以使用 [url=http://tdm-gcc.tdragon.net/]TDM-GCC[/url]。
设置编译和链接标志
我们使用 import “C” 导入的是一个伪包(pseudo-package),我们通过其来使用 C 代码。在 import “C” 之前,紧跟着 import “C” 的注释可以包括:
编译器和链接器标志
C 代码
我们可以通过 #cgo 指令来设置编译器和链接器标志,例如:
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
附带提及一点的是,这些指令中可以包含构建约束(build constraint),详细内容见:[url]http://golang.org/pkg/go/build/#hdr-Build_Constraints[/url]。
常用的 #cgo 指令有:
CPPFLAGS、CFLAGS 指令被用于编译当前包中的 C 文件(任何的 .c、.s、.S 文件)
CPPFLAGS、CXXFLAGS 指令被用于编译当前包中的 C++ 文件(任何的 .cpp、.cc、.cxx 文件)
LDFLAGS 指令用于指定链接器标志
pkg-config 指令用于通过 pkg-config 工具获取编译器和链接器标志(例如:#cgo pkg-config: png cairo)
在 Golang 的工具发现存在使用 import “C” 的 Golang 源文件时,它将会查找当前目录下的非 Golang 源文件并编译它们作为此 Golang 包的一部分:
文件 test.c
#include <stdio.h>
void sayHi() {
printf("Hi");
}
文件 test.go
package main
/*
extern void sayHi();
*/
import "C"
func main() {
C.sayHi()
}
进行构建工作:
go build
需要注意的是,使用 go build test.go 将不会编译 test.c 文件。
Golang 引用 C
结构体上需要注意的点:
C 结构体的域名称如果为 Golang 的关键字时,访问时需要在域名称前面加上 _。比如说,C 中有一个结构体变量 x,此变量对应的结构体中有一个域 type,那么在 Golang 中需要通过 x._type 来访问 type 域
结构体的位域、非对齐数据等无法在 Golang 中表示时会被忽略
Golang 结构体中不能使用 C 类型的域
标准的 C 数值类型对应:
C.char
C.schar(signed char)
C.uchar(unsigned char)
C.short
C.ushort(unsigned short)
C.int
C.uint(unsigned int)
C.long
C.ulong(unsigned long)
C.longlong(long long)
C.ulonglong(unsigned long long)
C.float
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
其他需要注意的点:
C 语言中的 void* 对应 unsafe.Pointer
C 语言中的结构、联合、枚举类型(而非变量),在 Golang 中需要加上 struct_、union_、enum_ 前缀访问。由于 Golang 中没有联合这种数据类型,因此 C 的联合在 Golang 中被表示为字节数组
和 C 语言等价的那些类型是不可以导出的
C 引用 Golang
Golang 的函数可以导出给 C 使用:
//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
对应的 C 代码为(被生成在 _cgo_export.h 中):
extern int64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
有几点需要注意:
Golang 函数的多个返回值会被映射为一个 C 结构体
使用 //export 来使得 Golang 函数可以在 C 中引用。在使用了 //export 之后,此 Golang 源文件中就不能包含 C 的定义(但可以存在声明)
References:
[url]http://name5566.com/4934.html?utm_source=tuicool[/url]