C 语言与 Golang 相互调用的简单例子。

在此使用一段简单的代码展示 CGO 的基本用法 —— 在 Go 程序中使用 C 语言编程。

使用 C 源码编译

项目目录结构:

project/
    - main.go
    - add/
        - add.h
        - add.c
        - add.go

add.hadd.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 展示了对库函数的调用。AddMul 展示了对自定义函数的调用。

因为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 知识可以从这里获取