-
Notifications
You must be signed in to change notification settings - Fork 14
cgo
golang的cgo支持调用C++的方法:extern "C"
c.h c.c封装了c++代码
https://www.cnblogs.com/sohoer2003/p/4329085.html
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test();
#ifdef __cplusplus
}
#endif
需要被go调用的函数声明写入 extern "C"
package main
// #cgo LDFLAGS: -L . -lc_test -lstdc++
// #cgo CFLAGS: -I ./
// #include "c.h"
import "C"
func main(){
C.test()
}
#cgo LDFLAGS:需要链接的库路径 #cgo CFLAGS: c文件所在位置
/*
#cgo LDFLAGS: -L/usr/local/lib -L../../build/src -lmyshare -lsnark -stdc++ -lgmp -lgmpxx
#cgo CFLAGS: -I ../
#include "wraplibsnark.hpp"
*/
-lsnark是libsnark的动态库 -lmyshare是封装接口后的动态库 -lgmp -lgmp++一定要加(原因在于内部引用类这两个库 可从cmakelist看出) (此方法来自云象 使用libsnark.so来自zokrates拷贝 源libsnark进行了修改 不适用于该项目开发)
目前将部分动态库拷贝至/usr/local/lib下 如运行go程序时提示找不到动态库,需要export LD_LIBRARY_PATH=/usr/local/lib命令行输入,此方法仅本次有效
该方法需修改cmakelist,将所有cmakelist.txt中static改为shared
/*
#cgo LDFLAGS: -L/usr/local/lib -lzk_wrap -lzm -lff -lsnark -lstdc++ -lgmp -lgmpxx
#include "../wraplibsnark.hpp"
*/
-lzk_wrap -lzm -lff -lsnark均需添加到/usr/local/lib中
c go 类型对比
char --> C.char --> byte
signed char --> C.schar --> int8
unsigned char --> C.uchar --> uint8
short int --> C.short --> int16
short unsigned int --> C.ushort --> uint16
int --> C.int --> int
unsigned int --> C.uint --> uint32
long int --> C.long --> int32 or int64
long unsigned int --> C.ulong --> uint32 or uint64
long long int --> C.longlong --> int64
long long unsigned int --> C.ulonglong --> uint64
float --> C.float --> float32
double --> C.double --> float64
void * -> unsafe.Pointer
C -> Go
int(C.int ) //普通类型这样
// C string to Go string
func C.GoString(*C.char) string
// C string, length to Go string
func C.GoStringN(*C.char, C.int) string
// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
Go -> C
C.char
C.schar (signed char)
C.uchar (unsigned char)
C.short
C.ushort (unsigned short)
C.int
C.uint (unsigned int)
C.long
C.ulong (unsigned long)
C.longlong (long long)
C.ulonglong (unsigned long long)
C.float
C.double.
unsafe.Pointer ----(void*)
// Go string to C string
func C.CString(string) *C.char
var val []byte
(*C.char)(unsafe.Pointer(&val[0]))
在我们以“C.*”的形式调用 C 语言代码库时,有一点需要特别注意。在 C 语言中,如果一个函数的参数是一个具有固定尺寸的数组, 那么实际上这个函数所需要的是指向这个数组的第一个元素的指针。C 编译器能够正确识别和处理这个调用惯例。它可以自行获取到这 个指针并传给函数。但是,这在我们使用 cgo 工具调用 C 语言代码库时是行不通的。在 Go 语言中,我们必须显式的将这个指向数 组的第一个元素的指针传递给C语言的函数,像这样:C.func1(&x[0])。
在 C 语言中没有像 Go 语言中独立的字符串类型。C 语言使用最后一个元素为‘\0’的字符数组来代表字符串。在 Go 语言的字符串和 C 语言的字符串之间进行转换的时候,我们就需要用到代码包 C 中的 C.CString、C.GoString 和 C.GoStringN 等函数。这些转换 操作是通过对字符串数据的拷贝来完成的。Go 语言内存管理器并不能感知此类内存分配操作。因为它们是由 C 语言代码引发的。所以, 我们在使用与 C.CString 函数类似的会导致内存分配操作的函数之后,需要调用代码包 C 的 free 函数以手动的释放内存。这里有 一个小技巧,即我们可以把对 C.free 函数的调用放到 defer 语句中或者放入在 defer 之后的匿名函数中。这样就可以保证在退出 当前函数之前释放这些被分配的内存了。
cs := C.CString(s) //Go 语言的字符串转换为了C语言的字符串 cs 变量的类型是 *C.Char defer C.free(unsafe.Pointer(cs))
如果想直接访问 C 语言中的 struct、union 或 enum 类型的话,就需要在名称前分别加入前缀 struct_、union 或 enum。比如, 我们需要在 Go 源码文件中访问C语言代码中的名为 command 的 struct 类型的话,就需要这样写:C.structcommand。那么,如果 我们想在Go语言代码中访问C语言类型struct中的字段需要怎样做呢?解决方案是,同样以 C 语言类型 struct 的实例名以及选择符“.” 作为前导,但需要在字段的名称前加入下划线“”。例如,如果 command1 是名为 command 的 C 语言 struct 类型的实例名,并且这 个类型中有一个名为 name 的字段,那么我们在 Go 语言代码中访问这个字段的方式就是command1._name。 需要注意的是,我们不能在 Go 的 struct 类型中嵌入 C 语言类型的字段。
标记 CFLAGS 可以指定用于 gcc 中的 C 编译器的选项。它常常用于指定头文件(.h 文件)的路径。 而标记 LDFLAGS 则可以指定 gcc 编译器会用到的一些优化参数,也可以用来告诉链接器需要用到的C语言代码库文件的位置。