CGO —— Golang 与 C 语言混合编程
C 语言与 Golang 相互调用的简单例子。
在此使用一段简单的代码展示 CGO 的基本用法 —— 在 Go 程序中使用 C 语言编程。
使用 C 源码编译
项目目录结构:
project/
- main.go
- add/
- add.h
- add.c
- add.go
在 add.h
、add.c
中,分别定义已经实现了两数相加的函数 add
:
// add.h
int add(int a, int b);
// add.c
#include "add.h"
int add(int a, int b) {
return a + b;
}
在 add.go
中,对 C 语言实现的函数 add
进行了一次封装,以便外部调用:
package add
/*
#include "add.h"
#include <stdio.h>
#include <stdlib.h>
int mul(int a, int b) {
return a * b;
}
*/
import "C"
import (
"unsafe"
)
func HelloWorld() {
s := C.CString("Hello World!")
C.puts(s)
C.free(unsafe.Pointer(s))
}
func Add(a, b int) int {
return int(C.add(C.int(a), C.int(b)))
}
func Mul(a, b int) int {
return int(C.mul(C.int(a), C.int(b)))
}
其中的 import "C"
表示使用了 CGO 。在这条语句前面的注释是一段 C 语言代码。
这里就定义了哪些 C 语言函数被引用。也可以在这里直接编写函数并实现。
因为这个特殊的语法,import “C” 必须单独一行,不可与其他包一起引用。
可以看到在代码中引用了头文件 add.h
以及 C 标准库的头文件,另外还实现了另一个两数相乘的函数 mul
。
在 Golang 中通过使用 C.xxx
的方式调用 C 函数。HelloWorld
展示了对库函数的调用。Add
和 Mul
展示了对自定义函数的调用。
因为Golang 和 C 有各自的变量类型。所以传参时候需要进行类型转换。
HelloWorld
在传参时使用 C.CString
将 Golang 字符串类型转换为 C 语言类型。
因为 C.CString
是在堆上分配空间存放字符串,需要调用者自己释放,所以最后调用 C.free
释放该字符串。
点击这里获取更多类型转换的知识。
最后在 main.go
中引用 add
包:
package main
import (
"fmt"
// import package add
"./add"
)
func main() {
add.HelloWorld()
fmt.Println(add.Add(10, 5))
fmt.Println(add.Mul(10, 5))
}
编译运行后可以看到输出:
Hello World!
15
50
其中 add.c
因为 import ./add
的引用而参与编译。
使用链接库
除了可以直接使用 C 源码编译 Go 程序,还可以:
- 调用 C 导出的静态库/动态库
- 把 Golang 编译成静态库/动态库供 C 其他程序调用。
参考
更多 CGO 知识可以从这里获取