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

发布于 2024-10-27 03:52:48 字数 257 浏览 4 评论 0原文

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

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

I have recently converted a library, I originally wrote in C++ with Boost Python wrapping, to C with SWIG wrapping to support more languages.
I switched from C++ to C because the library consists only of a set of functions and I also want the library to be callable from C (without having to compile the whole program with a C++ compiler).
However there is one thing that was not easy to port, a very small subset of the functions needs the ability to report errors back.
In C++/Boost Python that was very elegantly accomplished with throw and exception translation.

What would be the most elegant way (on both the C and wrapped language side) to have a subset of functions report errors?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橙味迷妹 2024-11-03 03:52:48

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

%{
    /* 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;
    }
}

This is how I do it. the %{...%} block inserts it's contents to the wrapper file. The %exception block is SWIG's exception handling, and runs after each function call to check if there was an error and throw an exception with PyErr_SetString if there was. Then, simply call "set_err("Error msg"); from your C function if you want to throw an exception.

%{
    /* 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;
    }
}

Alternatively if your C library uses a standard set of return codes you can replace this mechanism with a check of your function's return code in the %exception block.

%exception {
    int rc;
    rc = $action;

    if (rc == ERR) {
        PyErr_SetString(PyExc_RuntimeError, <err msg>);
        return NULL;
    }
}
悲欢浪云 2024-11-03 03:52:48

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

Take a look at Chapter 4 in C Interfaces and Implementations by Richard R. Hanson.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文