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使用官方版本,golang版avro使用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 slice、Go 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程序,细节、注意事项及其他在后续随笔中介绍。
参考文献:
- C? Go? Cgo! https://blog.golang.org/c-go-cgo
- Command cgo https://golang.org/cmd/cgo/
- Cgo https://github.com/golang/go/wiki/cgo
- cmd/cgo: Go type not supported in export: struct #18412
https://github.com/golang/go/issues/18412
C/C++调用Golang 二的更多相关文章
- .Net组件程序设计之远程调用(二)
.Net组件程序设计之远程调用(二) 激活模式 引用封送对象激活类型两种, 一种是客户端激活类型,一种是服务器端激活. 客户端激活对象 客户端激活方式:当客户端创建一个远程对象时,客户端得到的是一个新 ...
- C/C++调用Golang 一
C/C++调用Golang 一 (开发环境: 操作系统: windows 7 32位操作系统 C++: visual studio 2010 Golang:go version go1.9 windo ...
- 从源码(编译)安装golang 二
h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...
- 记一次坑爹的golang 二维map判断问题
记一次坑爹的golang 二维map判断问题 2018年10月18日 23:16:21 yinnnnnnn 阅读数:32更多 个人分类: golang 版权声明:本文为博主原创文章,未经博主允许不 ...
- 函数和常用模块【day04】:函数参数及调用(二)
本节内容 1.为什么要有参数 2.返回值 3.有参数函数调用 一.为什么要有参数? 无参数实现 def CPU报警邮件() #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 def 硬盘报警邮件() ...
- Android的JNI调用(二)
Android Studio 2.3在native下已经有了代码提示功能,按照提示下载相应组件就可以debug native代码. 一.Java调用JNI与JNI调用Java 1.1 C调用Java ...
- electron/nodejs实现调用golang函数
https://www.jianshu.com/p/a3be0d206d4c 思路 golang 支持编译成c shared library, 也就是系统中常见的.so(windows下是dll)后缀 ...
- Golang 二维切片初始化
package main import "fmt" func main() { // 方法0 row, column := 3, 4 var answer [][]int for ...
- golang 二维切片
初始化: res := make([][length]int, length), 例如: res := make([][2]int, 10) fmt.Println(res) 输出: [[0 0] [ ...
随机推荐
- UITextField的使用小技巧
[tf setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];//修改placeHolder ...
- java 之 适配器模式(大话设计模式)
适配器模式,笔者不是很推荐在项目初期阶段使用,在笔者看来这个设计模式就是套接了一层,从而达到能够迎合现有的外部接口规范. 先来简单的看下类图: 大话设计模式-类图 这个模式理解起来非常简单,A→B因为 ...
- MySql的技术规范-企业版(来源于MySql官网)
MySQL技术规范 Oracle MySQL云服务 MySQL数据库即服务 灵活的架构 开源 多线程 可插拔的存储引擎架构 InnoDB,NDB集群 MyISAM,合并,内存,存档 ANSI SQL标 ...
- Mac关机时处于黑屏状态
PS:不知道大家有没有遇到过mac电脑关机就黑屏,只有一个箭头,还可以滑动箭头,但就是黑屏状态,等个好长时间还是关不了机,因此我查了好多资料,原因是在关机时,mac要先关掉其他软件或者保存进程以备下次 ...
- 2016普及组t3海港
好的,说说这道题的思路,爆搜队列嘛: 用一个结构体队列存每个人来的时间和他的国籍,用一个vis数组存每个人来的次数,是第一次来sum便加一. 然后从前面第一个人开始扔(原谅我用这个词,因为我找不到更好 ...
- oracle触发器 调用 web接口
最近要求开发当数据表发生变化的时候调用web接口的需求,上网找了好几篇文章看着都觉得不是很好,也根据别人的思路去实现了下,感觉都不太理想,最后使用URLConnection实现了调用.具体查看一下代码 ...
- 《Clean Code》 代码简洁之道
作者介绍 原文作者: Robert C. Martin, Object Mentor公司总裁,面向对象设计.模式.UML.敏捷方法学和极限编程领域的资深顾问,是<敏捷软件开发:原则.模式.与实践 ...
- 【深度学习系列】用PaddlePaddle和Tensorflow实现经典CNN网络Vgg
上周我们讲了经典CNN网络AlexNet对图像分类的效果,2014年,在AlexNet出来的两年后,牛津大学提出了Vgg网络,并在ILSVRC 2014中的classification项目的比赛中取得 ...
- 40.Linux应用调试-使用gdb和gdbserver
1.gdb和gdbserver调试原理 通过linux虚拟机里的gdb,来向开发板里的gdbserver发送命令,比如设置断点,运行setp等,然后开发板上的gdbserver收到命令后,便会执行应用 ...
- Springboot 使用 JSR 303 对 Controller 控制层校验及 Service 服务层 AOP 校验,使用消息资源文件对消息国际化
导包和配置 导入 JSR 303 的包.hibernate valid 的包 <dependency> <groupId>org.hibernate.validator< ...