第一节 编译
- 第一步:将go代码生成so动态库 go build -o test.so -buildmode=c-shared main.go
— 结果:产生两个文件分别为test.h、test.so
— 作用:后续在C中用这两个文件即可 - 第二步:开发完C代码后,编译C代码 gcc test.c -o test ./test.so
— 注意:此处动态库前面的路径必须带,否则找不到.so库
— 扩展:C++代码同理g++ test.cpp -o test ./test.so
第二节 调用
第一步 先开发生成so库的go代码
- 规则一:通过export 暴露出so库对外的接口,参考如下代码,注意 export和注释之间不能有空格,必须是//export 函数名;
- 规则二:必须是main包,且含有main函数,main函数可以什么都不干,有main函数才能让cgo编译器去把包编译成c的库;
- 规则三:import “C”是必须的,如果没有import “C” 将只会build出一个.a文件,而缺少.h文件。
- 规则四:export里不支持Go语言的struct,故涉及结构体时必须使用C的结构体,使用方法就是通过注释的形式,此结构体变量名不受大小写约束,注意:必须在import "c"前面且紧挨,中间不能有空行;
- 规则五:基于规则四的结构体在go中使用时,前面必须加C.;
- 规则六:结构体字节对齐在go和c中没有区别;
package main
import "C"
import (
"fmt"
"unsafe"
)
func Age(Age int) {
fmt.Println("I am age", Age)
}
func Name(Name string) {
fmt.Println("I am name", Name)
}
func ModifyStruct(info *C.InfoS) {
fmt.Printf("%d %s\n", info.Age, C.GoString(&(info.Name[0])))
fmt.Println("go sizeof:", unsafe.Sizeof(C.InfoS{}))
info.Age = 18
info.he = 19
info.s = 20
}
func main() {
}
第二步:在C代码中调用go接口
- 规则一:通过#include包含go生成的.h头文件;
- 规则二:使用接口前最好先查看头文件中转换成C代码后的定义;
#include "test.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[] = "hahaa";
GoString name = {&buf, strlen(buf)};
Age(30);
Name(name);
InfoS st={20, "xiaoming"};
ModifyStruct(&st);
printf(" c sizeof: %d\n", sizeof(st));
printf("%d %s %d %d\n", st.Age, st.Name, st.he, st.s);
return 0;
}