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\r\n",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\r\n",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\r\n",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

 

                   

 

posted @ 2017-09-07 19:40  majianguo  阅读(7587)  评论(0编辑  收藏  举报