一个简单的例子混编Go与C

环境

一个完整可运行的例子

具体的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开发有一个大体的了解。更深一层的,则需要一些计算机基础知识的储备;好了,我要去看书了。

参考