趁着五一放假,趁着有时间,把欠的一些技术集中研究研究,写写文章,好给自己一个交待。
本文继续介绍如何在 Golang 中调用 C++ 函数。

起因

前面文章介绍的方式,在运行时需要指定动态库位置,或将动态库放置系统目录,对笔者而言,还是略有麻烦,本文将使用dl系列函数,在运行时加载动态库,这样就去掉了路径的依赖。

实现

为减少篇幅,仅摘录必要的源码。

封装

在动态库版本源码基础上,额外添加封装动态库头文件 c_callso.h:

#ifdef __cplusplus
extern "C" {
#endifint cso_init(char* soname);int cso_uninit();// 结构体指针,传入传出
int CSetPointA(Point* point, Point* point1);// 调用内部的类
//int FooCall(void);#ifdef __cplusplus
}
#endif

对应实现文件主要代码如下:

#include <dlfcn.h>void* g_sohandle = NULL;int cso_init(char* soname)
{g_sohandle = dlopen(soname, RTLD_LAZY);if (g_sohandle == NULL) return -1;return 0;
}int cso_uninit()
{if (g_sohandle != NULL) dlclose(g_sohandle);return 0;
}int CSetPointA(Point* point, Point* point1)
{typedef int (*ptr)(Point*, Point*);printf("in c file call so\n");ptr fptr = (ptr)dlsym(g_sohandle, "FooSetPointA");return (*fptr)(point, point1);
}

其中,CSetPointA 函数就是对接 FooSetPointA 函数的,仅做简单的封装。

调用

Golang 测试完整代码如下:


package main/*
#cgo LDFLAGS: -ldl#include <stdlib.h>
#include "c_callso.h"
#include "c_callso.c"
*/
import "C"import ("fmt""unsafe"
)var (csoname = "./libfoo.so1"//csoname = "./aXi3n0fr1.rd"
)func so_test() {fmt.Println("go c++ so test")soname := C.CString(csoname)ret := C.cso_init(soname)if ret != 0 {fmt.Println("cso_init failed ", ret)return }defer C.free(unsafe.Pointer(soname))defer C.cso_uninit()// C形式 结构体var myPoint, myPoint1 C.PointmyPoint.x = 100;myPoint.y = 200;myPoint.pinname = C.CString("Hello ") // 指针形式defer C.free(unsafe.Pointer(myPoint.pinname))// 固定长度数组,麻烦点arr := [16]C.char{}mystr := "Hell "for i := 0; i < len(mystr) && i < 15; i++ {arr[i] = C.char(mystr[i])}myPoint.inname = arr // 数组形式fmt.Println("Golang | org struct ", myPoint, "single: ", myPoint.x, myPoint.y, myPoint.pinname)// 结构体指针 传入传出ret = C.CSetPointA(&myPoint, &myPoint1)// 注:C++中使用字符串数组形式,转成stringvar carr []byte//carr = C.GoBytes(myPoint1.name, 100)for i := range myPoint1.name {if myPoint1.name[i] != 0 {carr = append(carr, byte(myPoint1.name[i]))}}gostr := string(carr) // 转成go的stringfmt.Println("Golang | c++ call ret: ", ret, myPoint1.x, gostr, myPoint1.name)// 注:直接用指针形式转换,此处的指针值,与在C中申请的值,是一致的// 注:如果指针没有分配内存,返回string为空,用unsafe.Pointer返回<nil>gostr = C.GoString(myPoint1.pname)defer C.free(unsafe.Pointer(myPoint1.pname))fmt.Println("Golang | out pointer:", gostr, unsafe.Pointer(myPoint1.pname))
}func main() {so_test()
}

与前面文章示例不同的地方,主要是调用了 C.cso_init 初始化动态库,最终调用 cso_uninit 释放。

结果分析

运行时,只需要保持动态库的位置和名称与 Golang 中指定的一致即可,无须设置 LD_LIBRARY_PATH 环境变量。

go c++ so test
Golang | org struct  {100 200 [72 101 108 108 32 0 0 0 0 0 0 0 0 0 0 0] 0xe2fc10 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] <nil>} single:  100 200 0xe2fc10
in c file call so
C++ | got buf: Hell
C++ | pname: Hello
C++ | ptr: 0xe2fc30
Golang | c++ call ret:  0 101 name in c++ [110 97 109 101 32 105 110 32 99 43 43 0 0 0 0 0]
Golang | out pointer: Hell  | name in c++ malloc 0xe2fc30

总结

本文的方法,却增加了源码级别的复杂度,不一定都符合要求,因此仅作参考。
Linux 的动态库,其名称一般为 libXXX.so,但经测试,任意名称也是可以的。

李迟 2021.5.2

Golang实践录:调用C++函数的优化相关推荐

  1. Golang实践录:命令行cobra库实例优化

    本文上一文章<Golang实践录:命令行cobra库实例> 的优化,主要的子命令的业务实现的整理. 起因 旧版本中,每个子命令的入口函数,均需一一判断传入参数,并调用对应的业务实现函数,编 ...

  2. Golang实践录:命令行cobra库实例再三优化

    本文是上一文章<Golang实践录:命令行cobra库实例优化> 的优化,主要的子命令的业务实现的整理. 起因 上一版本实现的方式,还是有点不满意,格式也不对齐,重要的是,似乎不是正规的方 ...

  3. Golang实践录:调用C++函数

    趁着五一放假,趁着有时间,把欠的一些技术集中研究研究,写写文章,好给自己一个交待. 本文介绍如何在 Golang 中调用 C++ 函数. 起因 因工作需求,需要将一个工具由终端行的运行方式迁移到 we ...

  4. Golang实践录:生成版本号和编译时间

    本文介绍如何在 Golang 中生成和管理版本号及编译时间. 一.起因 笔者手上有几份祖传代码,最早一份90年代末写,次早是 2012 年写的,最新的代码,也是 2016 年写的,版本号倒有,但没有版 ...

  5. Golang实践录:简单的代码片段

    本文列出简单的代码片段及基础知识. 简单说明 包 import的包从src算,如果在子目录,一定要添加子目录路径.如import "a",则a一定在src目录下. 同一个目录只能有 ...

  6. Golang实践录:开篇

    自去年开始,因工作的关系,需要使用 Golang 进行开发.一来是工作,二来多了解一个新语言,总归是有好处.现在虽然不是主攻 Golang,但可能用来写一些小工具. 本系列不会系统介绍Golang,只 ...

  7. c语言 编译器优化没被调用的函数,编译器优化及优化问题的调试方法

    优化影响了那些内容 局部变量 这里提到的局部变量包含一个 block 中定义的局部变量以及参数传递中使用的局部变量. 这些局部变量可能会经历从栈里面分配到使用寄存器到直接移除的过程.这些局部变量都只是 ...

  8. Golang实践录:ssh及scp实现的优化

    本文对上文的实现的优化. 问题提出 上一文章中,基本上已经达到使用了,但为了适应更多场合,需要对上传.下载功能进行优化,本文实现对目录的传输. 设计思路 主要框架和上文相同,不再赘述.对于目录的支持, ...

  9. go 获得 mysql 实际运行 SQL,Golang实践录:一个数据库迁移的代码记录

    实现一个数据库迁移的案子.有些知识点值得记录. 技术框架 github.com/go-xorm/xorm:数据库操作 github.com/denisenkom/go-mssqldb:sqlserve ...

最新文章

  1. 火爆 GitHub!这个 AI 神器究竟有什么魅力?
  2. 看傻眼了,真的是软件测试福利来了,最全资料包
  3. layui富文本编译器添加图片
  4. 技术人看《长安十二时辰》的正确姿势是?
  5. myftpadmin+proftpd+mysql架设ftp服务器_linux下用Proftpd搭建ftp服务器及配置方法
  6. AD7705模数转换芯片工作原理
  7. 明翰英语教学系列之雅思写作篇V0.2(持续更新)
  8. NTL密码算法开源库(数论库)代码分析项目--综述
  9. 医院pacs系统服务器配置,浪潮为千佛山医院PACS系统开“药方”
  10. Oracle使用游标更新数据 Oracle游标之select for update和where current of 语句
  11. 金秋杭州游 只为桂花香
  12. ChatGPT保姆级教程,一分钟学会使用ChatGPT!
  13. GDAL / OGR 学习手册 [02] :栅格数据读取
  14. java编程括号匹配,Java正则表达式括号内容匹配
  15. SLAM 三维传感器 点滴
  16. Oracle导出数据并以指定分隔符来分隔字段
  17. 从WAP到RFID 移动小额支付关键技术浅析
  18. 什么是ArcGIS影像服务
  19. 华为服务器显示U10,什么是华为Hol-U10刷机前的双清
  20. revit卸载残留清理工具 v1.1

热门文章

  1. indesign照片放入太大_照片打印机,小米、华为到底哪家强?
  2. 定时更换超级连接的代码
  3. 5G iPhone SE即将试产 搭载A15仿生芯片采用4.7英寸屏幕
  4. 特斯拉员工薪酬曝光 最低54万元!
  5. 支持5G的iPhone SE Plus或将于明年面世
  6. 分析师称iPhone 13将支持卫星通信,但仅限特定市场
  7. 中国恒大拟出售恒大汽车2.66%股权 配股金额约106亿港元
  8. 传网易云音乐高管变动:市场副总裁李茵离职 CEO被降权
  9. 小米10至尊纪念版DXO第一 雷军:这是小米打拼三年第二次登顶
  10. 2020全国高考作文题出炉!网友:信心满满的点开,一脸懵逼的退出