C 语言中 Scala 的 Option 或 Rust 的 Result 错误处理

lem*_*r_a 5 c error-handling scala rust

在专业地使用 Scala 和 Python 一段时间后,我再次开始编写 C。在使用了 Scala 的“Option”和“Either”错误处理模式并最近尝试了 Rust 方式之后,我想要在 C 中使用类似的东西。所以我想出了这样的东西:

typedef struct {
    int age;
    char* name;
} User;

typedef struct {
    char* error;
    User* value;
} UserResult;

UserResult get_user() {
    /* Some complicated user fetching process .. that fails */
    return (UserResult) { .error = "403 Unauthorized\n" };
}

int main(void) {
    UserResult res = get_user();
    if (res.error)
        handle_error(res.error);
    if (res.value)
        do_something(res.value);
    /* ... */
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但这并不是真的安全(我们可以访问无效的指针)。我怎样才能得到类似于 Scala 或 Rust 处理 C 错误的方法?

编辑:更正 UserResult 字段名称“值”

Sir*_*ius 5

有很多方法可以处理现有 C 代码中的错误。如此之多以至于理解如何处理各种库的错误是一种不可忽视的心理负担,在项目中同时使用多个库时更是如此。

引入一种处理错误的新方法可能是有益的,但另一方面,它可能类似于这部著名的 XKCD 漫画

Rust(和 Scala 等)方式确实非常强大,并且比其他旧习语有一些优势。

但是, Result 习惯用法基于Sum Types,C 语言本身并不支持它。无法保证您UserResult处于一致状态。user并且error可以是空的,也可以是非空的。

这可以稍微修改一下,例如通过使用联合来代替:

typedef struct{
    union {
        char* error;
        User user;
    }
    bool has_error;
} UserResult;
Run Code Online (Sandbox Code Playgroud)

has_error标志指示实际填充了哪个字段:

int main(void) {
    UserResult res = get_user();
    if (res.has_error)
        handle_error(res.error);
    else
        do_something(res.value);
    /* ... */
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这并不完美,因为 C 语言不会强制执行正确的联合访问,而是在使用不当时调用未定义的行为