C 在第一次检测到错误后返回错误代码

C 在第一次检测到错误后返回错误代码,c,if-statement,return,C,If Statement,Return,我有一个函数,它执行一些初始化并调用其他函数,每个函数都返回一个错误代码。我希望在第一次检测到如下错误后能够从此函数返回: int error_code = FirstFunction(); if (error_code != 0) { return error_code; } error_code = SecondFunction(); if (error_code != 0) { return error_code; } // etc... 然而,这不仅看起来相当麻烦,而且

我有一个函数,它执行一些初始化并调用其他函数,每个函数都返回一个错误代码。我希望在第一次检测到如下错误后能够从此函数返回:

int error_code = FirstFunction();
if (error_code != 0) {
    return error_code;
}
error_code = SecondFunction();
if (error_code != 0) {
    return error_code;
}
// etc...
然而,这不仅看起来相当麻烦,而且还有多个返回声明,出于合规性原因,在我的公司这是不允许的

如何重新安排该语句,以便只有一个return语句,但在第一个错误代码之后仍然停止?我能想到的唯一方法是执行嵌套的if语句:

int error_code = FirstFunction();
if (error_code == 0) {
    error_code = SecondFunction();
    if (error_code == 0) {
        error_code = ThirdFunction();
        // etc...
    }
}
return error_code;
但这很快就会变得不合理。还有别的办法吗

编辑:在我的程序中,返回代码0表示成功(正常),非零表示失败/错误(不正常)

这将只返回第一个返回非零的函数。其思想是,对于
if
语句,第一个返回
非零
的函数将短路整个计算,并从返回非零
错误
的函数返回
错误
。另外一件事是赋值语句的值是赋值。这就是为什么这是有效的

一个更简单的方法是按顺序进行

if( error_code = FirstFunction() ) {}
else if( error_code = SecondFunction() ) {}
...

return error_code; 

好的,有一个在Linux内核中使用:

int somefunc(whatever)
{
    if (do_something()) {
        ret = -EINVAL;
        goto err;
    }
    if (do_something_else()) {
        ret = -EPERM;
        goto err;
    }
    /* ... */
    ret = 0;
err:
    some_mandatory_cleanup();
    return ret;
}
但我怀疑这会更不受欢迎。(在你尖叫之前,关键是最后的强制清理。
goto
将它安排为始终执行,但仍然将其排除在外。)


真的,我认为您的第一个代码片段中的代码很好,问题在于您的指导原则。即使我们只写
返回错误代码在一个地方,仅保证保存在变量中的错误代码始终正确或函数完成所有可能需要的清理是不够的。(考虑分配内存的东西,在任何情况下都必须释放它。)

如果所有这些函数都采用相同类型的参数并具有相同的返回类型,您可以将它们放在函数数组中并对其进行迭代。当发现错误时,它只是跳出循环并返回

 int (*function_array[max_array])();
 /*Fill the array with the functions you need*/

 for(i=0;i<max_array;i++){
    if((error_code=function_array[i]())!=OK){
        break;
    }
}

return error_code;
int(*函数数组[max\u数组])();
/*用所需的函数填充数组*/

对于(i=0;i您不必嵌套所有函数调用,下面的代码也可以完成这项工作,并且应该遵守您的代码编写规则:

error_code = FirstFunction();
if (error_code == 0) {
    error_code = SecondFunction();
}
if (error_code == 0) {
    error_code = ThirdFunction();
}
// etc...
return error_code;
精干干净(,但避免不喜欢的
goto
s):

顺便说一句,这遵循了更常见的模式:
0
正常,其他一切都不正常。根据需要进行调整)


您甚至可以使用宏来混淆这一点:

#define RUN_AND_BREAK_ON_ERROR(rc, f, ...) \
  if (0 != (rc = f(__VA_ARGS__))) \
  { \
    break; \
  } 

int foo(void)
{
  int error_code;

  do {
    RUN_AND_BREAK_ON_ERROR(error_code, FirstFunction, <args go here>);
    RUN_AND_BREAK_ON_ERROR(error_code, SecondFunction, <args go here>);
    ...

  } while (0);

  return error_code;
}
#定义错误时的运行和中断(rc,f,…)\
如果(0!=(rc=f(_VA_ARGS__)))\
{ \
中断\
} 
int foo(无效)
{
int错误代码;
做{
在出错时运行和中断(错误代码,第一个函数,);
在出错时运行和中断(错误代码,第二个函数,);
...
}而(0);
返回错误代码;
}

这是另一种精益方法,根据哪个功能失败,它可以返回不同的错误代码:

int func(void)
{
    int code;
    int error_code = (code = FirstFunction()) ? code :
                     (code = SecondFunction()) ? code :
                     (code = ThirdFunction()) ? code : 0;

    /* ... */

    return error_code;
}

所以当它是
1
时,您将返回?0以外的任何值。0表示无错误,非零表示错误发布
error\u code
的类型。虽然我很想更改这些指导原则,但它们是我们客户的总体项目要求的一部分,我无法控制。是的,如果我尝试使用goto:d,他们会解雇我。这很接近,我喜欢它在比较中捕获错误代码的方式,但是Benoit的答案和我想的有点接近。注意:2
else
是不需要的。@chux:你是说最后一个吗?早些时候,我输入了两次调用
FirstFunction
。您的意思是吗?不需要
else
s,因为当
if
条件失败时,执行
return
;但在第二个例子中,OP的问题不是为了避免多个返回点吗?@DavidBowling.:编辑。事实上,我已经提供了
{}
-如果
也可以,那么一个空白的
。我知道OP没有提到参数,但是,这种方法,使用一个函数指针数组,依赖于所有使用相同参数的函数,参数和类型都是一样的。我确实没有想到这一点。也许可以用另一个参数数组来解决。但在这一点上,这可能并不值得。@AnttiHaapala:为什么?为什么这种事经常发生在我身上……:}可能是1,3,7-三甲基黄嘌呤缺乏综合征;)还是太多的Visual Basic
#define RUN_AND_BREAK_ON_ERROR(rc, f, ...) \
  if (0 != (rc = f(__VA_ARGS__))) \
  { \
    break; \
  } 

int foo(void)
{
  int error_code;

  do {
    RUN_AND_BREAK_ON_ERROR(error_code, FirstFunction, <args go here>);
    RUN_AND_BREAK_ON_ERROR(error_code, SecondFunction, <args go here>);
    ...

  } while (0);

  return error_code;
}
int func(void)
{
    int code;
    int error_code = (code = FirstFunction()) ? code :
                     (code = SecondFunction()) ? code :
                     (code = ThirdFunction()) ? code : 0;

    /* ... */

    return error_code;
}