使用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(&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
————————————————
版权声明:本文为CSDN博主「橙zzzz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/o___GRoot/article/details/129668595

posted @ 2023-05-11 22:52  jiftle  阅读(755)  评论(1编辑  收藏  举报