最近需要在 go 中去调用 .so 库去完成一些事情,go 方面,利用 cgo 可以顺利的调用 .so 中的方法,但是有个问题是 go 没法捕获 .so 那边出现的异常。如果 .so 那边异常了,那么会带崩 go 程序,这不是我们想看到的。例如在 服务器应用中,某个异常的请求可能会把服务器进程给弄挂,这不是我们想看到的。

我们最好在可能会崩溃的地方进行异常捕获,可以做一层 wrapper,然后将错误信息传给 go 这边,让 go 去决定异常的处理方式,这里我写了一个简单的 Demo 进行验证。

首先我们写一个简单的 cpp 的库,做成 .so

  • foo 函数增加了 try catch,将异常信息通过 char* 返回给 go;
  • foo1 函数值抛出异常,不捕获;
// clib.h
#ifdef __cplusplus
extern "C" {
#endif #include <stdlib.h> typedef struct HANDLE_ERR {
char *data;
const char *pstrErr;
} HANDLE_ERR; HANDLE_ERR foo (const char *pstrArgs); char* foo1 (const char *pstrArgs); #ifdef __cplusplus
}
#endif // clib.cpp
#include <string.h>
#include <stdio.h>
#include <exception>
#include "clib.h" struct MyException : public std::exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
}; HANDLE_ERR foo (const char *pstrArgs) {
HANDLE_ERR result = {0};
try {
if (pstrArgs == nullptr)
throw MyException();
result.data = "Hello word!";
} catch(MyException &e) {
result.data = nullptr;
result.pstrErr = strdup(e.what());
}
return result;
} char* foo1 (const char *pstrArgs) {
if (pstrArgs == nullptr)
throw "exception, nullptr";
char* data = "Hello word!";
return data;
}

我们用 g++ 来做成 .so,将上面的 cpp 做成 libclib.so 文件,供 go 来使用,下面是用 g++ 编译的指令命令。

g++ -c -fPIC clib.cpp
g++ -shared -fPIC -o libclib.so clib.o

在做好了 .so 后,我们用 go 来调用

  • passNullptr 传递一个空指针给 clib,clib 会抛出异常;
  • passNormal 传递正常的值
  • passNullptrNoException 传递空指针给 foo1 函数,foo1 没有捕获异常。
package main

// #cgo LDFLAGS: -L. -lclib
// #include <stdlib.h>
// #include "clib.h"
import "C" import (
"log"
"unsafe"
) func passNullptr() {
log.Println("1. passNullptr")
ret := C.foo(nil)
if ret.pstrErr != nil {
defer C.free(unsafe.Pointer(ret.pstrErr))
log.Println("clib error: ", C.GoString(ret.pstrErr))
} else {
log.Println("no error! from clib: ", C.GoString(ret.data))
}
log.Println("")
} func passNormal() {
log.Println("2. passNormal")
cArgs := C.CString("")
defer C.free(unsafe.Pointer(cArgs))
ret := C.foo(cArgs)
if ret.pstrErr != nil {
defer C.free(unsafe.Pointer(ret.pstrErr))
log.Println("clib error: ", C.GoString(ret.pstrErr))
} else {
log.Println("no error! from clib: ", C.GoString(ret.data))
}
log.Println("")
} func passNullptrNoException() {
log.Println("3. passNullptrNoException")
cArgs := C.CString("")
defer C.free(unsafe.Pointer(cArgs))
C.foo1(nil)
log.Println("")
} func main() {
passNullptr()
passNormal()
passNullptrNoException()
}

下面是输出的结果

2022/08/27 15:47:21 1. passNullptr
2022/08/27 15:47:21 clib error: C++ Exception
2022/08/27 15:47:21
2022/08/27 15:47:21 2. passNormal
2022/08/27 15:47:21 no error! from clib: Hello word!
2022/08/27 15:47:21
2022/08/27 15:47:21 3. passNullptrNoException
libc++abi: terminating with uncaught exception of type char const*
SIGABRT: abort
PC=0x7ff811758112 m=0 sigcode=0 goroutine 0 [idle]:
runtime: unknown pc 0x7ff811758112
stack: frame={sp:0x7ff7bfefed28, fp:0x0} stack=[0x7ff7bfe803e8,0x7ff7bfeff450)
...
...
exit status 2

我们可以看到,加了 try catch 后,clib 将 error 信息传递到了 go 侧,如果不 try catch 异常,clib 的异常会把 go 进行给带崩溃,所以在 go 调用 .so 的时候,最好做一层 wrapper 做一下异常处理。

[Golang] cgo 调用 .so 捕获异常问题的更多相关文章

  1. golang cgo 使用总结

    原文地址 CGO 提供了 golang 和 C 语言相互调用的机制.某些第三方库可能只有 C/C++ 的实现,完全用纯 golang 的实现可能工程浩大,这时候 CGO 就派上用场了.可以通 CGO ...

  2. Dapr Golang HTTP 调用

    Dapr Golang HTTP 调用 版本介绍 Go 版本:1.15 Dapr Go SKD 版本:0.11.1 工程结构 从上图可知,新建 3 个 Go 启动项目,cmd 为启动项目目录,其中 c ...

  3. Linux golang使用cgo调用C++标准库问题

    我们知道cgo无法直接调用c++方法,但是可以通过c包装c++方法,以达到使用的目的. C++中,我们经常会用到STL.在cgo中,如果要调用STL,需要作如下操作: //cgo LDFLAGS: - ...

  4. golang通过cgo调用lua

    目录 1.前期准备 2.测试go代码 3.完成的一个学习项目 4.总结 1.前期准备 1.第三方库:https://github.com/aarzilli/golua 2.下载lua源码:https: ...

  5. golang动态调用方法

    package main import ( "fmt" "reflect" ) type YourT1 struct { } func (y *YourT1) ...

  6. C/C++调用Golang 二

    C/C++调用Golang 二 <C/C++调用Golang 一>简单介绍了C/C++调用Golang的方法步骤,只涉及一个简单的函数调用.本文总结具体项目中的使用场景,将介绍三种较复杂的 ...

  7. Golang调用Python

    https://yq.aliyun.com/articles/117329 Python是时髦的机器学习御用开发语言,Golang是大红大紫的新时代后端开发语言.Python很适合让搞算法的写写模型, ...

  8. electron/nodejs实现调用golang函数

    https://www.jianshu.com/p/a3be0d206d4c 思路 golang 支持编译成c shared library, 也就是系统中常见的.so(windows下是dll)后缀 ...

  9. Golang 调用 Python 代码

    go 中的 cgo 模块可以让 go 无缝调用 c 或者 c++ 的代码,而 python 本身就是个 c 库,自然也可以由 cgo 直接调用,前提是指定正确的编译条件,如 Python.h 头文件( ...

随机推荐

  1. Mac Book安装Windows发烫的问题

    Mac Book安装Windows后,电脑发烫,风扇一直高速旋转.针对此问题百度搜索了一下, 大多数人说更改电源选项,由"平衡"模式改为"节能"模式,亲身体验了 ...

  2. 华为云Stack首席架构师:打造“称手”的数字化工具,答好政企IT数字化转型这道必选题

    摘要:数字化转型是一号位工程,数字化的工具本身就是企业的核心竞争力. 本文分享自华为云社区<华为云Stack首席架构师:打造"称手"的数字化工具,答好政企IT数字化转型这道必 ...

  3. Visual Studio Installer下载速度为0处理办法

    DNS改为:223.5.5.5即可. 223.5.5.5 下载完成后记得改回来.

  4. 龙芯发布 .NET 6 SDK 6.0.105-ea1 LoongArch64 版本

    龙芯平台.NET,是龙芯公司基于开源社区.NET独立研发适配的龙芯版本,我们会长期进行安全更新和错误修复,并持续进行性能优化.社区.NET7版本开始已经原生支持LoongArch64架构源码.具备如下 ...

  5. 有关安装pycocotools的办法

    1,首先需要安装Visual C++ 2015构建工具,地址https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425- ...

  6. 记住这几个git命令就够了

    git clone: 下载初始化git add:添加git commit -m ' ' :提交 带消息git push:推送git pull: 拉取 git config --global user. ...

  7. 关于vue cli 使用iview 自定义主题遇到的坑

    定制主题,这里讲变量覆盖 当你老老实实的把上面文档中的代码一一复制粘贴到项目文件中时,发现了还没装less,所以你就 npm install less –savenpm install less-lo ...

  8. 从Hadder看蛋白质分子中的加氢算法

    技术背景 PDB(Protein Data Bank)是一种最常用于存储蛋白质结构的文件.而我们在研究蛋白质构象时,往往更多的是考虑其骨架,因此在很多pdb文件中直接去掉了氢原子.但是在我们构建蛋白质 ...

  9. python小题目练习(七)

    题目:实现如下图所示结果 代码实现: """Author:mllContent:模拟火车订票系统Date:2020-11-16"""# 定义 ...

  10. 用python整个URL缩短器

    URL缩短 短网址由于易于记忆和输入,因此在数字营销领域非常受欢迎. 这里给大家介绍一下,如何使用Python创建URL缩短器. python答疑 咨询 学习交流群2:660193417### fro ...