使用golang编写支持C++调用的动态库,接口支持结构体和回调函数
网上有很多例子介绍如何使用cgo实现C/C++与golang进行接口交互。
我有个项目是使用Qt写的客户端程序,但Qt在需要使用redis、支持表单的web服务、mq或网络化日志库等需求时,往往需要加载一大堆第三方库,且编译复杂,跨平台(如Windows/linux arm/linux x86)编译时较为复杂。
鉴于有使用golang的一些经验基础,遂想以golang实现一个工具库,在需要进行功能拓展时在工具库中进行接口增加即可。
在这个过程中遇到以下2个主要问题:
如何实现具备结构体传入和传出的接口
如何实现具备C++设定回调函数的接口
以下是代码示例:
一、实现具备结构体传入和传出的接口
package main
/*
#include <stdbool.h>
#include <string.h>
typedef struct {
int intVal;
bool boolVal;
char charArray[512];
} ParamInfo;
typedef struct {
int intVal;
bool boolVal;
char charArray[512];
} ResultInfo;
*/
import "C"
import (
"fmt"
"unsafe"
)
//export calcResult
func calcResult(paramInfoPtr *C.ParamInfo, resultInfoPtr *C.ResultInfo) C.int {
// Convert paramInfo to Go struct
paramInfo := &ParamInfo{
intVal: int(paramInfoPtr.intVal),
boolVal: bool(paramInfoPtr.boolVal),
charArray: C.GoString((*C.char)(unsafe.Pointer(¶mInfoPtr.charArray))),
}
fmt.Printf("go print:%v\n", paramInfo)
// Call your Go function here with paramInfo and resultInfo
resultInfo := yourFunction(paramInfo)
// Convert resultInfo from Go struct to C struct
resultInfoPtr.intVal = C.int(resultInfo.intVal)
resultInfoPtr.boolVal = C.bool(resultInfo.boolVal)
copy((*[512]byte)(unsafe.Pointer(&resultInfoPtr.charArray))[:], []byte(resultInfo.charArray))
return C.int(0) // Return 0 or whatever error code you want to indicate success or failure
}
type ParamInfo struct {
intVal int
boolVal bool
charArray string
}
type ResultInfo struct {
intVal int
boolVal bool
charArray string
}
func yourFunction(paramInfo *ParamInfo) *ResultInfo {
// Your logic goes here
return &ResultInfo{
intVal: 123,
boolVal: true,
charArray: "Hello, Qt!",
}
}
func main() {
// Do nothing, just needed for `go build` to work
}
二、实现具备C++设定回调函数的接口
由于C++的函数定义与golang的函数定义并不一致,实现回调函数主要思路是:1. 提供接口可以根据函数原型传递回调函数指针2.回调函数指针需要在cgo代码中进行声明 3.回调的真实处理需要以go代码调用C++函数的方式进行回调。
以下两段代码 第一个是main.go文件,第二个是一个中转文件 命名为bridge.go (回调函数的声明和实现需要放到2个文件中,否则编译时会报重复定义)
main.go:
package main
/*
#include <stdlib.h>
typedef void ( *CallbackFunc_T )( char *, int );
extern CallbackFunc_T pCallFuncPtr;
extern void callBackFunc(char *str, int num);
*/
import "C"
import (
"fmt"
"unsafe"
)
//export setCallback
func setCallback(cb C.CallbackFunc_T) {
C.pCallFuncPtr = cb
fmt.Println("setCallback")
}
//export triggerCallback
func triggerCallback() {
// 如果存在回调函数,使用提供的参数调用回调函数
str := C.CString("Hello from Golang")
C.callBackFunc(str, C.int(42))
defer C.free(unsafe.Pointer(str))
}
func main() {}
bridge.go:
package main
/*
typedef void ( *CallbackFunc_T )( char *, int );
CallbackFunc_T pCallFuncPtr = NULL;
void callBackFunc(char *str, int num)
{
if(pCallFuncPtr != NULL){
pCallFuncPtr(str,num);
}
};
*/
import "C"
golang编译输出为动态库的命令是:go build -buildmode=c-shared -o xxx.dll
————————————————
版权声明:本文为CSDN博主「橙zzzz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/o___GRoot/article/details/129668595