zoukankan      html  css  js  c++  java
  • C/C++调用Golang 二

    C/C++调用Golang

    C/C++调用Golang 一》简单介绍了C/C++调用Golang的方法步骤,只涉及一个简单的函数调用。本文总结具体项目中的使用场景,将介绍三种较复杂的调用方式:一,C++golang传入复杂结构体;二,C++golang传入回调函数,在golang中调用C++函数;三,C++调用golang函数,返回复杂的结构体。

    (本文后面涉及三个例子,省略了编译步骤,仅展示关键代码。具体操作步骤参考《C/C++调用Golang 一》)

    C++golang传入复杂结构体

    采用avro来序列化与反序列化结构体。C++avro使用官方版本,golangavro使用gopkg.in/alanctgardner/gogen-avro.v4 。(C++代码省略了avro结构体的序列化与反序列化,仅展示C++Golang的交互部分)

    1.1 Golang 代码

    package main

    import "C"

    import "fmt"

    //export WriteData

    func WriteData(data []byte) int {

        fmt.Println("WriteData ", data, len(data))

        return 0

    }

    func main() {

    }

    编译生成的头文件

    /* Created by "go tool cgo" - DO NOT EDIT. */

    /* package c_references_to_go/sample1 */

    /* Start of preamble from import "C" comments.  */

    /* End of preamble from import "C" comments.  */

    /* Start of boilerplate cgo prologue.  */

    #line 1 "cgo-gcc-export-header-prolog"

    #ifndef GO_CGO_PROLOGUE_H

    #define GO_CGO_PROLOGUE_H

    typedef signed char GoInt8;

    typedef unsigned char GoUint8;

    typedef short GoInt16;

    typedef unsigned short GoUint16;

    typedef int GoInt32;

    typedef unsigned int GoUint32;

    typedef long long GoInt64;

    typedef unsigned long long GoUint64;

    typedef GoInt32 GoInt;

    typedef GoUint32 GoUint;

    //typedef __SIZE_TYPE__ GoUintptr;

    typedef float GoFloat32;

    typedef double GoFloat64;

    //typedef float _Complex GoComplex64;

    //typedef double _Complex GoComplex128;

    /*

      static assertion to make sure the file is being used on architecture

      at least with matching size of GoInt.

    */

    typedef char _check_for_32_bit_pointer_matching_GoInt[sizeof(void*)==32/8 ? 1:-1];

    typedef struct { const char *p; GoInt n; } GoString;

    typedef void *GoMap;

    typedef void *GoChan;

    typedef struct { void *t; void *v; } GoInterface;

    typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

    #endif

    /* End of boilerplate cgo prologue.  */

    #ifdef __cplusplus

    extern "C" {

    #endif

    extern GoInt WriteData(GoSlice p0);

    #ifdef __cplusplus

    }

    #endif

    1.2 C++代码

    #include <Windows.h>

    #include <stdio.h>

    #include "sample1.h"

    //#include "LargeStruct.h"

    typedef GoInt (*funcPtrWriteData)(GoSlice p0);

    int main(){

    HMODULE h = LoadLibraryA("sample1.dll");

    if (NULL == h || INVALID_HANDLE_VALUE == h)

    {

    return -1;

    }

    funcPtrWriteData pfWriteData = (funcPtrWriteData)GetProcAddress(h,"WriteData");

    if (pfWriteData)

    {

    /* LargeStruct ls;

    ls.ID = "100001";

    ls.Name = "Peter";

    Pet pet;

    pet.Type = "Dog";

    pet.Name = "WangCai";

    pet.Age = 5;

    ls.Pets.push_back(pet);*/

    GoSlice p0;

    p0.data = 0;  //serial ls to binary

    p0.len = p0.cap = 0;  //binary len

    pfWriteData(p0);

    }

    FreeLibrary(h);

    return 0;

    }

    C++golang传入回调函数

    2.1 Golang 代码

    设置回调需要中间的桥接函数 CReportData

    package main

    import (

        "fmt"

    )

    /*

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    typedef int (*ptfFuncReportData)(const char* data,int len);

    extern int CReportData(ptfFuncReportData pf,const char* data,int len);

    */

    import "C"

    import (

        "bytes"

        "c_references_to_go/sample3/avro_struct"

        "unsafe"

    )

    var callBackFunc C.ptfFuncReportData

    //export SetCallBack

    func SetCallBack(f C.ptfFuncReportData) {

        callBackFunc = f

    }

    //export BeginWork

    func BeginWork() {

        go func() {

            for index := 0; index < 10; index++ {

                var ls avro_struct.LargeStruct

                ls.ID = fmt.Sprintf("ID%d", 1000+index)

                ls.Name = fmt.Sprintf("Peter%d", index)

                ls.Pets = []*avro_struct.Pet{&avro_struct.Pet{Type: "Dog", Name: "WangCai", Age: 5}}

                var buf bytes.Buffer

                ls.Serialize(&buf)

                dataSlice := buf.Bytes()

                GoReportData(dataSlice)

            }

        }()

    }

    func GoReportData(data []byte) {

        C.CReportData(callBackFunc, (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)))

    }

    func main() {

    }

    bridge.c

    #include "_cgo_export.h"

    int CReportData(ptfFuncReportData pf,const char* data,int len){

        return pf(data,len);

    }



    编译后产生的头文件

    /* Created by "go tool cgo" - DO NOT EDIT. */

    /* package c_references_to_go/sample2 */

    /* Start of preamble from import "C" comments. */

    #line 7 "Y:\mygo\src\c_references_to_go\sample2\main.go"

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    typedef int (*ptfFuncReportData)(const char* data,int len);

    extern int CReportData(ptfFuncReportData pf,const char* data,int len);

    #line 1 "cgo-generated-wrapper"

    /* End of preamble from import "C" comments. */

    /* Start of boilerplate cgo prologue. */

    #line 1 "cgo-gcc-export-header-prolog"

    #ifndef GO_CGO_PROLOGUE_H

    #define GO_CGO_PROLOGUE_H

    typedef signed char GoInt8;

    typedef unsigned char GoUint8;

    typedef short GoInt16;

    typedef unsigned short GoUint16;

    typedef int GoInt32;

    typedef unsigned int GoUint32;

    typedef long long GoInt64;

    typedef unsigned long long GoUint64;

    typedef GoInt32 GoInt;

    typedef GoUint32 GoUint;

    typedef __SIZE_TYPE__ GoUintptr;

    typedef float GoFloat32;

    typedef double GoFloat64;

    typedef float _Complex GoComplex64;

    typedef double _Complex GoComplex128;

    /*

    static assertion to make sure the file is being used on architecture

    at least with matching size of GoInt.

    */

    typedef char _check_for_32_bit_pointer_matching_GoInt[sizeof(void*)==32/8 ? 1:-1];

    typedef struct { const char *p; GoInt n; } GoString;

    typedef void *GoMap;

    typedef void *GoChan;

    typedef struct { void *t; void *v; } GoInterface;

    typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

    #endif

    /* End of boilerplate cgo prologue. */

    #ifdef __cplusplus

    extern "C" {

    #endif

    extern void SetCallBack(ptfFuncReportData p0);

    extern void BeginWork();

    #ifdef __cplusplus

    }

    #endif

    2.2 C++代码

    #include <Windows.h>

    #include <stdio.h>

    #include "sample2.h"

    typedef void (*funcPtrSetCallBack)(ptfFuncReportData p0);

    typedef void (*funcPtrBeginWork)();

    int OnReportData(const char* data,int len){

    printf("OnReportData %x %d ",data,len);

    return 0;

    }

    int main(){

    HMODULE h = LoadLibraryA("sample2.dll");

    if (NULL == h || INVALID_HANDLE_VALUE == h)

    {

    return -1;

    }

    funcPtrSetCallBack pfSetCallBack = (funcPtrSetCallBack)GetProcAddress(h,"SetCallBack");

    funcPtrBeginWork pfBeginWork = (funcPtrBeginWork)GetProcAddress(h,"BeginWork");

    if (pfSetCallBack)

    {

    pfSetCallBack(OnReportData);

    }

        if (pfBeginWork)

        {

    pfBeginWork();

        }

    Sleep(1000*10);

    FreeLibrary(h);

    return 0;

    }

    运行之后的输出:

     

    C++调用golang函数返回复杂结构体

    不能向C++程序返回Go sliceGo struct。(详情见master分支 src/cmd/cgo/doc.go ,参考5

    3.1 Golang代码

    package main

    import (

        "bytes"

        "unsafe"

    )

    /*

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    typedef struct {

         char* Data;

         int DataLen;

    } GetLargeStruct_return;

    extern GetLargeStruct_return* CopyLargeSturct(char* data,int dataLen);

    extern void FreeLargeSturct(GetLargeStruct_return* ptr);

    */

    import "C"

    import (

        "c_references_to_go/sample3/avro_struct"

    )

    //export GetLargeStruct

    func GetLargeStruct(paraIn int) *C.GetLargeStruct_return {

        var ls avro_struct.LargeStruct

        ls.ID = "1000001"

        ls.Name = "Peter"

        ls.Pets = []*avro_struct.Pet{&avro_struct.Pet{Type: "Dog", Name: "WangCai", Age: 5}}

        var buf bytes.Buffer

        ls.Serialize(&buf)

        dataSlice := buf.Bytes()

        return C.CopyLargeSturct((*C.char)(unsafe.Pointer(&dataSlice[0])), C.int(len(dataSlice)))

    }

    //export FreeLargeStruct

    func FreeLargeStruct(ptr *C.GetLargeStruct_return) {

        C.FreeLargeSturct(ptr)

    }

    //export GetLargeStruct2

    func GetLargeStruct2(paraIn int) (*C.char, int) {

        var ls avro_struct.LargeStruct

        ls.ID = "1000001"

        ls.Name = "Peter"

        ls.Pets = []*avro_struct.Pet{&avro_struct.Pet{Type: "Dog", Name: "WangCai", Age: 5}}

        var buf bytes.Buffer

        ls.Serialize(&buf)

        dataSlice := buf.Bytes()

        return (*C.char)(unsafe.Pointer(C.CBytes(dataSlice))), len(dataSlice)

    }

    //export FreeCBytes

    func FreeCBytes(ptr *C.char) {

        C.free(unsafe.Pointer(ptr))

    }

    func main() {

    }

    C函数源码文件 (释放C分配的内存)

    #include "_cgo_export.h"

    GetLargeStruct_return* CopyLargeSturct(char* data,int dataLen){

         GetLargeStruct_return* result = (GetLargeStruct_return*)malloc(sizeof(GetLargeStruct_return));

         result->DataLen = dataLen;

         result->Data = 0;

         if(dataLen>0){

         result->Data = malloc(dataLen);

         memcpy(result->Data,data,dataLen);

         }

         return result;

    }

    void FreeLargeSturct(GetLargeStruct_return* ptr){

         if(ptr != 0){

             if(ptr->Data != 0 ){

                 free(ptr->Data);

             }

             free(ptr);

         }

    }

    编译后产生的头文件

    /* Created by "go tool cgo" - DO NOT EDIT. */

    /* package c_references_to_go/sample3 */

    /* Start of preamble from import "C" comments. */

    #line 8 "Y:\mygo\src\c_references_to_go\sample3\main.go"

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    typedef struct {

       char* Data;

       int DataLen;

    } GetLargeStruct_return;

    extern GetLargeStruct_return* CopyLargeSturct(char* data,int dataLen);

    extern void FreeLargeSturct(GetLargeStruct_return* ptr);

    #line 1 "cgo-generated-wrapper"

    /* End of preamble from import "C" comments. */

    /* Start of boilerplate cgo prologue. */

    #line 1 "cgo-gcc-export-header-prolog"

    #ifndef GO_CGO_PROLOGUE_H

    #define GO_CGO_PROLOGUE_H

    typedef signed char GoInt8;

    typedef unsigned char GoUint8;

    typedef short GoInt16;

    typedef unsigned short GoUint16;

    typedef int GoInt32;

    typedef unsigned int GoUint32;

    typedef long long GoInt64;

    typedef unsigned long long GoUint64;

    typedef GoInt32 GoInt;

    typedef GoUint32 GoUint;

    typedef __SIZE_TYPE__ GoUintptr;

    typedef float GoFloat32;

    typedef double GoFloat64;

    typedef float _Complex GoComplex64;

    typedef double _Complex GoComplex128;

    /*

    static assertion to make sure the file is being used on architecture

    at least with matching size of GoInt.

    */

    typedef char _check_for_32_bit_pointer_matching_GoInt[sizeof(void*)==32/8 ? 1:-1];

    typedef struct { const char *p; GoInt n; } GoString;

    typedef void *GoMap;

    typedef void *GoChan;

    typedef struct { void *t; void *v; } GoInterface;

    typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

    #endif

    /* End of boilerplate cgo prologue. */

    #ifdef __cplusplus

    extern "C" {

    #endif

    extern GetLargeStruct_return* GetLargeStruct(GoInt p0);

    extern void FreeLargeStruct(GetLargeStruct_return* p0);

    /* Return type for GetLargeStruct2 */

    struct GetLargeStruct2_return {

      char* r0;

      GoInt r1;

    };

    extern struct GetLargeStruct2_return GetLargeStruct2(GoInt p0);

    extern void FreeCBytes(char* p0);

    #ifdef __cplusplus

    }

    #endif

    3.2 C++ 代码

    #include <Windows.h>

    #include <stdio.h>

    #include "sample3.h"

    typedef GetLargeStruct_return* (*funcPtrGetLargeStruct)(GoInt p0);

    typedef void (*funcPtrFreeLargeStruct)(GetLargeStruct_return* p0);

    typedef struct GetLargeStruct2_return (*funcPtrGetLargeStruct2)(GoInt p0);

    typedef void (*funcPtrFreeCBytes)(char* p0);

    int main(){

    HMODULE h = LoadLibraryA("sample3.dll");

    if (NULL == h || INVALID_HANDLE_VALUE == h)

    {

    return -1;

    }

    funcPtrGetLargeStruct pfGetLargeStruct = (funcPtrGetLargeStruct)GetProcAddress(h,"GetLargeStruct");

    funcPtrFreeLargeStruct pfFreeLargeStruct = (funcPtrFreeLargeStruct)GetProcAddress(h,"FreeLargeStruct");

    if (pfGetLargeStruct)

    {

    GetLargeStruct_return* result = pfGetLargeStruct(5);

    if (result)

    {

    printf("GetLargeStruct(5) return  %x %d ",result->Data,result->DataLen);

    if (pfFreeLargeStruct)

    {

    pfFreeLargeStruct(result);

    }

    }

    }

    funcPtrGetLargeStruct2 pfGetLargeStruct2 = (funcPtrGetLargeStruct2)GetProcAddress(h,"GetLargeStruct2");

    funcPtrFreeCBytes pfFreeCBytes = (funcPtrFreeCBytes)GetProcAddress(h,"FreeCBytes");

    if (pfGetLargeStruct)

    {

    GetLargeStruct2_return result = pfGetLargeStruct2(5);

    printf("GetLargeStruct2(5) return  %x %d ",result.r0,result.r1);

    if (pfFreeCBytes)

    {

    pfFreeCBytes(result.r0);

    }

    }

    FreeLibrary(h);

    return 0;

    }

    运行之后的输出:

     

     

    本文只讲述C/C++怎么调用golang程序,细节、注意事项及其他在后续随笔中介绍。

    参考文献:

    1. C? Go? Cgo!      https://blog.golang.org/c-go-cgo  
    2. Command cgo     https://golang.org/cmd/cgo/
    3. Cgo             https://github.com/golang/go/wiki/cgo
    4. cmd/cgo: Go type not supported in export: struct #18412

                      https://github.com/golang/go/issues/18412

    1. https://go.googlesource.com/go/+/master/src/cmd/cgo/doc.go

                       

  • 相关阅读:
    Element库的Vue版本ElementUI的本地引入方法
    在Win7操作系统上安装VS2017报错:安装程序清单签名验证失败
    [转]五大主流浏览器及四大内核
    [转]idea2021.1破解版 附安装教程免激活码
    [转]Node.js安装详细步骤教程(Windows版)
    [转]Windows系统下彻底删除Windows.old 文件夹的方法
    Springboot+Vue进行Web开发时特别需要注意的小事项
    基带信号与频带信号,基带传输与频带传输各是什么?两者有什么区别?
    springboot的Web项目编译运行时提示错误:Field userService in com.cetc.UserManger.controller.UserController required a bean of type 'com.cetc.UserManger.service.UserService' that could not be found.
    创建springboot项目时出现Selected Java version 11 is not supported by SDK (maximum 8)
  • 原文地址:https://www.cnblogs.com/majianguo/p/7491508.html
Copyright © 2011-2022 走看看