一个简单的例子混编Go与C
环境
- MacOS:10.13.4
- Golang: version go1.10.1 darwin/amd64
- IDE:VSCode 1.24.0
一个完整可运行的例子
具体的Cgo使用,可以参考这一篇博客。但是下面依然给出一个可运行的示例,供参考。
package main
// 下面的 import "C" 以及其前面的两个 #include 必须这么写
// go编译器会根据 import "C" 前面的注释引入两个C的header
//
// 不能这么做:
// 1. 不能把 import "C" 和下面的import合并,否则go编译器不认
// 2. 不能在 import "C" 与前面的注释插入空行,否则go编译器也不认
/*
#include <stdlib.h>
#include <stdio.h>
*/
import "C"
import (
"fmt"
"unsafe"
)
// Random 调用了C库中的 random 函数
// 由于C库中的 random 函数返回的是C语言的long类型,
// 因此需要通过 int(C.random) 进行一次声明的转换,把
// C语言的long类型转换为Go的int类型
func Random() int {
return int(C.random())
}
// Seed 指定C库random函数的seed值
// C.uint(i)把传入golang的int转换声明为C语言的uint类型
func Seed(i int) {
C.srandom(C.uint(i))
}
// Print 字符串示意函数
// 这里我们首先通过 C.CString(s) 把传入的字符串转变类型为
// C字符串(根据各方内容推测,应该包括两步:①malloc声明一块
// 内存;②把Go里的字符串内容拷贝到内存;③返回字符串首地址。)
// 因为Go的GC无法管理C语言里的内存,因此这里需要显式free掉。
func Print(s string) {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
C.fputs(cs, (*C.FILE)(C.stdout))
}
func main() {
Seed(620)
fmt.Println(Random())
Print("mikk\n")
}
如果运行,可以观察到输出:
381675317
mikk
TODO
看了一下源码,发现Cgo这边的源码涉及比较多Golang运行时中的M、P、G概念,且有一些基础的函数调用栈帧的知识要再捡起来。
推荐把参考中的文章看一遍,能对Cgo开发有一个大体的了解。更深一层的,则需要一些计算机基础知识的储备;好了,我要去看书了。
参考
- Cgo命令 官方Cgo文档
- C与Go与Cgo 官方关于Cgo的Blog
- CGO简明教程 对Cgo进行介绍的博客
- Using C Dynamic Libraries In Go Programs Go, (Golang) Programming 在MacOS上的一个Cgo混编实践,包含有动态链接库的使用
- CGO,GOLANG调用C库,调用代码、静态库或动态库