網上有很多例子介紹如何使用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