SWIG封装的C库引发异常的优雅方法
我最近把一个库从C++转换成了C,这个库最开始是用C++写的,并且用Boost Python进行了封装。现在我用SWIG进行了C的封装,这样可以支持更多的编程语言。我之所以从C++转到C,是因为这个库其实只是一些函数,而且我希望这个库可以直接用C调用(这样就不需要用C++编译器编译整个程序了)。
不过,有一件事转移过来并不简单,就是有一小部分函数需要能够报告错误。在C++和Boost Python中,这个功能是通过throw
和异常处理来优雅实现的。
那么,有什么好的方法可以让这部分函数在C和封装后的语言中都能报告错误呢?
2 个回答
0
看看理查德·R·汉森的《C接口与实现》第四章。
5
这是我处理的方式。%{...%} 这个块的内容会插入到包装文件中。%exception 块是 SWIG 的异常处理部分,它会在每次函数调用后运行,检查是否有错误发生,如果有的话,就会用 PyErr_SetString 抛出一个异常。然后,如果你想在 C 函数中抛出异常,只需简单地调用 "set_err("错误信息");"。
%{
/* Exception helpers */
static int swig_c_error_num = 0;
static char swig_c_err_msg[256];
const char *err_occurred()
{
if (swig_c_error_num) {
swig_c_error_num = 0;
return (const char*)swig_c_err_msg;
}
return NULL;
}
void set_err(const char *msg)
{
swig_c_error_num = 1;
strncpy(swig_c_err_msg, msg, 256);
}
%}
%exception {
const char *err;
$action
if (err = err_occurred()) {
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
}
另外,如果你的 C 库使用了一套标准的返回代码,你可以在 %exception 块中用检查函数的返回代码来替代这个机制。
%exception {
int rc;
rc = $action;
if (rc == ERR) {
PyErr_SetString(PyExc_RuntimeError, <err msg>);
return NULL;
}
}