GO语言调用C++ 库最好用的还是需要用swig来做个中转库,会把相关的类给你转换好,但有时如果只是调用C++写的一些函数,不是类,就可以不要中转,
如在CTP开发过程中,用到了DataCollect的库,头文件如下:
#ifndef DATA_COLLECT_H
#define DATA_COLLECT_H
///获取AES加密和RSA加密的终端信息 pSystemInfo的空间需要调用者自己分配 至少270个字节
/// macOS 返回值定义
/* 返回的int值 不为0 表示采集信息有误 具体哪个采集项有问题需要做如下判断
从低位开始分别标示 终端信息 -> CPU序列号
返回值 & (0x01 << 0) 不为0 表示终端类型未采集到
返回值 & (0x01 << 1) 不为0 表示 信息采集时间获取异常
返回值 & (0x01 << 2) 不为0 表示ip 获取失败 (采集多个相同类型信息的场景有一个采集到 即表示采集成功)
返回值 & (0x01 << 3) 不为0 表示mac 获取失败
返回值 & (0x01 << 4) 不为0 表示 设备名 获取失败
返回值 & (0x01 << 5) 不为0 表示 操作系统版本 获取失败
返回值 & (0x01 << 6) 不为0 表示 硬盘序列号 获取失败
返回值 & (0x01 << 7) 不为0 表示 CPU序列号 获取失败
*/
int CTP_GetSystemInfo(char* pSystemInfo, int& nLen);
///获取没有AES加密的终端信息
int CTP_GetSystemInfoUnAesEncode(char* pSystemInfo, int& nLen);
//版本号格式
//Sfit + 生产还是测试秘钥(pro/tst) + 秘钥版本 + 编译时间 + 版本(内部)
const char * CTP_GetDataCollectApiVersion(void);
#endif
这个头跟C没什么区别,如果我们直接#include 又不能调用,因为C与C++ 的库的实际函数名引用是不一样的,我们用nm看一下(头文件只用到CTP,这里过滤一下CTP):
这里就跟c++的头定义不一样了,不过他们的参数返回值是一样的,这样可以直接替换上这里的名称就可以用了,如:
_Z28CTP_GetSystemInfoUnAesEncodePcRi 就是 GetSystemInfoUnAesEncode
那c代码调用就可以直接这样写
char *result = (char *)malloc(270); // 分配堆内存
int ret = _Z28CTP_GetSystemInfoUnAesEncodePcRi(result, length);
if (ret == 0) {
result[*length] = '\0';
return result; // 返回指向堆内存的指针
}
free(result); // 错误时释放内存
GO用cgo 也是可以直接调用的:
来个完整调用例子:
package main
/*
#cgo LDFLAGS: -fPIC -L. -F/lib/lib-6.7 -Wl,-rpath,/lib/lib-6.7 -lctpgo -framework MacDataCollect -framework CoreFoundation -framework CoreFoundation -framework IOKit -framework Foundation
#cgo CPPFLAGS: -fPIC -I./ -I./include -g
#cgo CFLAGS: -fPIC -I./ -I./include -g
#include "stdio.h"
#include "stdlib.h"
extern int _Z28CTP_GetSystemInfoUnAesEncodePcRi(char* pSystemInfo, int* nLen);
//重命令一个,相当于转换
char* CTP_GetSystemInfoUnAesEncode(int *length){
char *result = (char *)malloc(270); // 分配堆内存
int ret = _Z28CTP_GetSystemInfoUnAesEncodePcRi(result, length);
if (ret == 0) {
result[*length] = '\0';
return result; // 返回指向堆内存的指针
}
free(result); // 错误时释放内存
return NULL;
}
*/
import "C"
//GO 包一个
func GetSystemInfoUnAesEncode() (string, int, error) {
var length C.int
result := C.CTP_GetSystemInfoUnAesEncode(&length)
if result != nil {
//error for object 0x16ba266da: pointer being freed was not allocated
//defer C.free(unsafe.Pointer(result)) // 使用C.free来释放内存
// 将C字符串转换为Go字符串
goStr := C.GoStringN(result, C.int(length))
//println(goStr)
return goStr, int(length), nil
}
return "", 0, nil
}
func main(){
str, l, err := GetSystemInfoUnAesEncode()
if err == nil {
println(l, len(str))
}
}
一个文件就行
源代码上GITHUB:
https://github.com/pinke/data_collect_go.git