GO调用C函数
在很多场景下,在Go的程序中需要调用c函数或者是用c编写的库(底层驱动,算法等,不想用Go语言再去造一遍轮子,复用现有的c库)。我们在使用Golang开发项目或系统的时候难免会遇到Go和C语言混合编程,这时很多人都会选择使用cgo
直接引用C函数
Go代码直接调用c函数
package main
import "fmt"
/*
#include <stdio.h>
void funcC(int a) {
printf("recv num is %d \n", a);
}
*/
import "C"
func main() {
var a C.int
a = 100
C.funcC(a)
fmt.Println("Test OK")
}
传递数组的场景
package main
/*
#include <stdio.h>
#include <string.h>
void fill_array(char *s) {
strcpy(s, "cobbliu");
}
void fill_2d_array(char **arr, int colSize) {
strcpy((char*)(arr + 0 * sizeof(char) * colSize), "hello");
strcpy((char*)(arr + 1 * sizeof(char) * colSize/sizeof(char*)), "cgo");
}
*/
import "C" // 注意这个地方与上面注释的地方不能有空行,并且不能使用括号如import ("C" "fmt")
import "fmt"
import "unsafe"
func main() {
var dir [10]byte
C.fill_array((*C.char)(unsafe.Pointer(&dir[0])))
fmt.Println(string(dir[:]))
//var dirs [4][16]byte
dirs := make([][]byte, 4)
for i := 0; i < 4; i++ {
dirs[i] = make([]byte, 16)
}
C.fill_2d_array((**C.char)(unsafe.Pointer(&dirs[0][0])), C.int(16))
fmt.Println(dirs)
}
调用so中的c函数
- 编译一个so
//源文件test.c
#include <stdio.h>
void funcC() {
printf("recv num is %d \n", a);
}
//头文件test.h
void funcC(int a)
//编译成动态库.so
gcc -c -fPIC -o test.o test.c
gcc -shared -o libtest.so test.o
//也可以直接生成so
gcc -fPIC -shared -o libtest.so test.c
- go文件
package main
import "fmt"
/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lhi
#include "hi.h" //非标准c头文件,所以用引号
*/
import "C"
func main() {
C.hi()
fmt.Println("Test ok")
}
- CFLAGS中的-I(大写的i) 参数表示.h头文件所在的路径
- LDFLAGS中的-L(大写) 表示.so文件所在的路径 -l(小写的L) 表示指定该路径下的库名称
- 直接运行go run main.go
- 如果引用不*.so, 将存入so的路径添加到环境变量当中: export LD_LIBRARY_PATH=/xxx/lib
- 也可以在 go build 的时候指定so的路径: go build -ldflags="-r ./" test.go。编译时指定连接目录