使用golang编写支持C++调用的动态库,接口支持结构体和回调函数

网上有很多例子介绍如何使用cgo实现C/C++与golang进行接口交互。

我有个项目是使用Qt写的客户端程序,但Qt在需要使用redis、支持表单的web服务、mq或网络化日志库等需求时,往往需要加载一大堆第三方库,且编译复杂,跨平台(如Windows/linux arm/linux x86)编译时较为复杂。

鉴于有使用golang的一些经验基础,遂想以golang实现一个工具库,在需要进行功能拓展时在工具库中进行接口增加即可。

在这个过程中遇到以下2个主要问题:

  1. 如何实现具备结构体传入和传出的接口

  1. 如何实现具备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(&paramInfoPtr.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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值