SWIG包装的C库抛出异常的最优雅方式是什么?

4
我最近将一份我用C++编写并使用Boost Python包装的库转换为使用SWIG包装的C代码,以支持更多语言。我从C++切换到C是因为该库仅由一组函数组成,我还希望该库可以从C中调用(而无需使用C++编译器编译整个程序)。然而,有一件事很难移植,即非常小的一部分函数需要能够报告错误。在C++ / Boost Python中,这可以通过throw和异常转换来实现。在C和封装的语言方面,最优雅的方式是什么,以便让一部分函数报告错误?
2个回答

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;
    }
}

0
请查看Richard R. Hanson所著的《C接口与实现》第4章。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接