C 中的短路错误处理

发布于 2024-07-17 04:17:47 字数 841 浏览 11 评论 0原文

我想知道是否有更好的方法来处理 C 中的情况,即在一系列表达式中遇到错误时希望立即退出函数。 (在本例中,它是一个在错误时返回 NULL 的函数)

,例如在某些 C 代码中,他们试图通过将一系列语句与 AND (&&) 组合来短路错误处理。

return doSomething() && 
     doSomething2() && 
     doSomething3() && ... ;

这让我很恼火,因为我们在一个声明中一行塞满了这么多内容。 但我想另一种选择是

if (!(value = doSomething()))
    return NULL;
if (!(value = doSomething2()))
    return NULL;
etc
return value;

但是我在 perl 和 bash 脚本中看到的短路错误评估呢?

int die(int retvalue) {
    exit(retvalue);
}
.....
(value = doSomething()) || die(1);
(value = doSomething2()) || die(2);
(value = doSomething3()) || die(3);
return value;

主要问题是 RHS 必须是一个表达式,所以你不能真正从功能。 有人会觉得这个有价值还是太有限了?

编辑:我想我应该在第一个示例中包含换行符。 问题是,如果您决定在中间添加另一个表达式,则需要小心。

I was wondering if there was a better way of handling the case in C where you want to exit a function as soon as you encounter an error in a series of expressions. (in this case, its a function that returns a NULL on error)

e.g. in some C code where they tried to short circuit error handling by combining a series of statements with AND (&&).

return doSomething() && 
     doSomething2() && 
     doSomething3() && ... ;

This irritates me since we're cramming so much on one line in one statement. But I guess the alternative is

if (!(value = doSomething()))
    return NULL;
if (!(value = doSomething2()))
    return NULL;
etc
return value;

But what about short circuit error evaluation that I've seen in perl and bash scripts..

int die(int retvalue) {
    exit(retvalue);
}
.....
(value = doSomething()) || die(1);
(value = doSomething2()) || die(2);
(value = doSomething3()) || die(3);
return value;

The main problem with this is that the RHS has to be an expression so you can't really goto or return from the function. Would anyone find this of value or is it too limited?

edit: I guess I should have meant to include newlines in the first example. The problem is that you need to be careful if you decide to add another expression in the middle.

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

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

发布评论

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

评论(6

放手` 2024-07-24 04:17:47

我已经看到在 C 中使用 GOTO 来达到这个目的。

因为 C 中没有“finally”结构,所以即使您提前退出函数,也需要一个方法来释放所有内存。

所以它本质上如下
(如果我错了,有人可以纠正我的 C 语法吗,我有点生疏)

int foo()
{
    /* Do Stuff */
    if(!DoSomething())
        GOTO Failure;

    if(!DoSomething2())
        GOTO Failure;

    if(!DoSomething3())
        GOTO Failure;

    /* return success */
    return true; 

    Failure:
    /* release allocated resources */
    /* print to log if necessary */
    return false;
}

重要说明
不要将 GOTO 用于执行流程。 它们只能在发生错误时使用,并且只能转到当前函数的末尾。 如果您将它们用于其他用途,那么您正在创建可能会破坏现实结构的意大利面条式代码。 只是不要这样做。

编辑

正如其中一位海报所指出的,使用 Exit(x) 将杀死整个程序,从而保留该解决方案以应对致命错误。 然而,您最初提出的解决方案(DS() && DS2() && DS3())都在一行上,这给错误处理带来了问题。

如果您想将函数包装在某种特定于函数的错误处理中,那么当您将函数调用全部包装在一行中时,就无法做到这一点。 因此,至少您可以执行类似的操作,

int result1 = 0;
int result2 = 0;
int result3 = 0;

result1 = DoSomething();

if(result1)
    result2 = DoSomething2();

if(result2)
    result3 = DoSomething3();

return result1 && result2 && result3;

因为此方法不会排除错误处理。

I've seen the use of GOTOs in C for this exact purpose.

Because there isn't a 'finally' construct in C, a method was needed to free all your memory even if you were exiting a function early.

So it's essentially as follows
(could someone correct my C syntax if I'm wrong, I'm a bit rusty)

int foo()
{
    /* Do Stuff */
    if(!DoSomething())
        GOTO Failure;

    if(!DoSomething2())
        GOTO Failure;

    if(!DoSomething3())
        GOTO Failure;

    /* return success */
    return true; 

    Failure:
    /* release allocated resources */
    /* print to log if necessary */
    return false;
}

Important note
Do not use GOTOs for execution flow. They should only be used on error, and only to go to the end of the current function. If you use them for anything else, you're creating spaghetti code that could possibly destroy the fabric of reality. Just don't do it.

EDIT

As one of the posters noted, using Exit(x) will kill your entire program, which keeps that solution reserved for fatal errors. However your original proposed solution (DS() && DS2() && DS3()) all on one line poses a problem for error handling.

If you wanted to wrap the functions in some sort of function specific error handling, there is no way to do it when you wrap the function calls all in one line. So, at the very least you could do something like

int result1 = 0;
int result2 = 0;
int result3 = 0;

result1 = DoSomething();

if(result1)
    result2 = DoSomething2();

if(result2)
    result3 = DoSomething3();

return result1 && result2 && result3;

Because this method would not preclude error handling.

爺獨霸怡葒院 2024-07-24 04:17:47

如果您唯一担心的是在一行中塞满太多代码,为什么不直接使用:

return doSomething()
    && doSomething2()
    && doSomething3()
    && ... ;

我倾向于将第二种情况写为:(

if (!(value = doSomething()))  return NULL;
if (!(value = doSomething2())) return NULL;
: : : : :
return value;

甚至排列返回值以使其可读),因为我喜欢在同一行上看到尽可能多的代码屏幕一次(您可以根据需要在行之间插入其他检查)。

If your only concern is cramming too much onto one line, why don't you just use:

return doSomething()
    && doSomething2()
    && doSomething3()
    && ... ;

I tend to write the second case as:

if (!(value = doSomething()))  return NULL;
if (!(value = doSomething2())) return NULL;
: : : : :
return value;

(even lining up the returns to make it readable) since I like to see as much code on a screen as once (and you can insert other checks in between the lines as needed).

祁梦 2024-07-24 04:17:47

像这样的事情怎么样?

int result;

result = doSomething();

result = result && doSomething2();

result = result && doSomething3();

return result;

这以与第一个示例类似的方式使用短路,但它允许您将其分成多行并添加注释等。

How about something like this?

int result;

result = doSomething();

result = result && doSomething2();

result = result && doSomething3();

return result;

This uses short-circuiting in a similar way to your first example, but it allows you to break it onto multiple lines and add comments etc.

自此以后,行同陌路 2024-07-24 04:17:47

我建议反对您提出的技术。 首先,C中的exit终止进程; 它不只是回归。 所以它仅限于少数致命错误的情况。

在我看来,您试图避免的第一个解决方案是最好且最容易理解的。

I recommend against your proposed technique. At first, exit in C terminates the process; it not just returns. So it is limited to only few cases of fatal errors.

The first solution you are trying to avoid is the best and easiest understood in my point of view.

同尘 2024-07-24 04:17:47

根据我的经验,用 C 语言编写此代码的惯用方法是使用一系列 if 语句来启动函数,这些语句检查函数其余部分的前置条件。 如果不满足前置条件,则立即返回并带有错误代码。 这样,当您到达函数体的主要部分时,您就知道一切正常,并且可以使代码尽可能简单。

换句话说,你采用第二种方法。

举个例子,可以编写一个函数来复制字符串,如下所示:(

int copy_string(char *source, char *target, size_t max)
{
    if (source == NULL)
        return -1;
    if (target == NULL)
        return -1;
    source_len = strlen(source);
    if (source_len + 1 > max)   // +1 for NUL
        return -1;
    memcpy(target, source, source_len + 1);
    return 0;
}

我喜欢 Unix 系统调用约定,错误时返回 -1,但这是一个有争议的风格问题,与这个问题无关。)

The idiomatic way of writing this in C is, in my experience, is to start the function with a series of if statements that check of pre-conditions of the rest of the function. If a pre-condition is not met, an immediate return with an error code is done. This way, when you get to the main part of the body of the function, you know that everything is OK and can keep the code as simple as possible.

In other words, you second approach.

As an example, one might write a function to copy a string as follows:

int copy_string(char *source, char *target, size_t max)
{
    if (source == NULL)
        return -1;
    if (target == NULL)
        return -1;
    source_len = strlen(source);
    if (source_len + 1 > max)   // +1 for NUL
        return -1;
    memcpy(target, source, source_len + 1);
    return 0;
}

(I like the Unix system call convention of returning -1 for errors, but that's a debatable matter of style and irrelevant to this question.)

不必你懂 2024-07-24 04:17:47

我以前见过这个:

int Function (void)
{
    int Result = DoSomething();

    if (Result) Result = DoSomething2();
    if (Result) Result = DoSomething3();
    if (Result) Result = DoSeomthing4();

    return Result;
}

它看起来足够整洁,很容易对齐。 它不会立即退出,但不会执行任何其他操作。 当然,这假设函数在成功时返回非零。 否则,如果函数在失败时返回非零,您可以简单地使用 if (!Result)

I've seen this before:

int Function (void)
{
    int Result = DoSomething();

    if (Result) Result = DoSomething2();
    if (Result) Result = DoSomething3();
    if (Result) Result = DoSeomthing4();

    return Result;
}

It looks neat enough, easily alignable. It won't exit straight away but it won't execute anything else. This of course assumes that functions return non-zero on success. Otherwise you could simply use if (!Result) if functions return non-zero on failure.

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