最近需要在 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. Linux文本搜索及截取操作

    Linux文本搜索及截取操作 cat 查看 grep 搜索 awk 截取 查看dna-server.xml 文件的内容 [root@localhost servers]# cat cwag9002/w ...

  2. 写selenium常用到的js代码

    selenium可以运行JavaScript代码,可以用一些JavaScript来辅助编写Selelnium代码. 1.scrollIntoView - 向下拉滚动条,使得某元素可见 IWebElem ...

  3. 封装环形加载进度条(Vue插件版和原生js版)

    1.效果预览 2.用到的知识 主要利用SVG的stroke-dasharray和stroke-dashoffset这两个属性. 在看下面文章之前,你需要了解 <!DOCTYPE html> ...

  4. windows下docker部署报错

    报错信息:Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:8848 -> 0.0.0 ...

  5. MySql查看索引以及各字段含义

    查看表的索引: show index from userInfo(表名) show index from 数据库名.表名 查看某表某一列上的索引使用下面的SQL语句: show index from ...

  6. Linux环境下ProxyChains应用网络代理

    1.下载源码 git clone https://github.com.cnpmjs.org/rofl0r/proxychains-ng.git 或者 https://hub.fastgit.org/ ...

  7. HashSet底层HashMap源码分析

    在看HashSet源码的时候,意外发现底层HashMap保存的value居然不是null,而是保存一个Object作为Value.顿觉有悖常理,于是来分析一下: HashSet的add方法: publ ...

  8. Winsock Client Code

    以下代码来自MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591(v=vs.85).aspx #define W ...

  9. C++指针和结构体基础知识

    学习C++首先要回忆起C语言当中的指针和结构体知识,本文作者将通过一段代码来总结指针和结构体基础知识:指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址.就像其他变量或常量一样,您必须在使 ...

  10. 多重分派(multiple dispatch)与访问者模式

    什么是双重分派 什么是分派(dispatch) 首先我们需要理解「分派」的含义.分派就是将方法调用与对应的具体方法绑定起来.而判断的依据有两点,这两者可称为「宗量」: 方法的接收者,也就是哪个对象调用 ...