前言

cgo 提供了 golang 和 C 语言相互调用的机制。几乎所有的编程语言都有C语言的影子,当然golang也不例外。可以看到golang的创始者们与C语言有着密切的联系。下面我们将通过快速入门小例子来掌握cgo的基本用法。

最简cgo程序

真实的cgo程序一般都比较复杂。不过我们可以通过一个小例子,了解一个最简的cgo程序该是什么样的。

构造一个最简cgo程序,首先要忽视一些复杂的cgo特性,同时要展示cgo程序和纯Go程序的差别来。

在使用cgo特性之前,需要安装C/C++构建工具链,在macOS和Linux下是要安装gcc,在windows下是需要安装MinGW工具。

下面是我们构建的最简cgo程序:



编译输出:



对上面的代码进行说明。代码通过import "C"语句启用cgo特性,主函数只是通过Go内置的println函数输出字符串,其中并没有任何和cgo相关的代码。虽然没有调用cgo的相关函数,但是go build命令会在编译和链接阶段启动gcc编译器,这已经是一个完整的cgo程序了。


基于C标准库函数


编译输出:


我们不仅仅通过import "C"语句启用cgo特性,同时包含C语言的#include <stdlib.h>头文件。

注意下:



如果你运行go tool cgo main.go转换上面的例子,你会发现在本地文件夹下生成了一个_obj的文件夹:



它会包含一个编译器在编译这些C文件后生成的目标文件cgo.o。

使用自己的C函数

前面我们使用了标准库中已有的函数。现在我们先自定义一个叫SayHello的C函数来实现打印,然后从Go语言环境中调用这个SayHello函数:



编译输出:



除了SayHello函数是我们自己实现的之外,其它的部分和前面的例子基本相似。

我们也可以将SayHello函数放到当前目录下的一个C语言源文件中(后缀名必须是.c)。因为是编写在独立的C文件中,为了允许外部引用,所以需要去掉函数的static修饰符。



然后在CGO部分先声明SayHello函数,其它部分不变:



编译:


注意,如果之前运行的命令是go run hello.go或go build hello.go的话,此处须使用go run .或go build .



既然SayHello函数已经放到独立的C文件中了,我们自然可以将对应的C文件编译打包为静态库或动态库文件供使用,关于静态库和动态库以后再讲解。


总结


Go导出函数供C开发者使用(目前这种需求应该很少见),如果你正准备使用Go开发你的程序,或者你正将一个C构建的项目转换成Go项目,请尽量使用Go构建你的项目,而不是偷巧的导入C代码,尽量保持Go项目的纯粹。



公众号【程序猿编码】