SWIG最优雅的方式包装C库来引发异常

时间:2011-03-27 09:11:08

标签: python c swig

我最近将一个库(我最初用C ++编写,使用Boost Python包装)转换为C语言,并使用SWIG包装来支持更多语言。 我从C ++切换到C,因为该库只包含一组函数,我也希望该库可以从C调用(无需用C ++编译器编译整个程序)。 然而,有一件事不容易移植,一小部分功能需要能够报告错误。 在C ++ / Boost Python中,使用throw和异常翻译非常优雅。

有一个函数子集报告错误的最优雅方式(在C语言和包装语言方面)会是什么?

2 个答案:

答案 0 :(得分:5)

我就是这样做的。 %{...%}块将其内容插入到包装文件中。 %异常块是SWIG的异常处理,并在每次函数调用后运行以检查是否存在错误,如果存在则抛出PyErr_SetString异常。然后,只需调用“set_err(”Error msg“);如果要抛出异常,则从C函数调用。

%{
    /* 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 {
    int rc;
    rc = $action;

    if (rc == ERR) {
        PyErr_SetString(PyExc_RuntimeError, <err msg>);
        return NULL;
    }
}

答案 1 :(得分:0)

请参阅Richard R. Hanson的C接口和实现中的第4章。