使用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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章