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

Posted

技术标签:

【中文标题】第一次检测到错误后返回错误代码【英文标题】:Return error code after first detected error 【发布时间】:2018-05-17 06:25:47 【问题描述】:

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

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 表示成功(OK),非零表示失败/错误(NOT OK)

【问题讨论】:

那么1你会回来吗? 0 以外的任何值。0 表示没有错误,非零表示错误 发布error_code的类型。 【参考方案1】:

您不必嵌套所有的函数调用,下面的代码也可以完成这项工作,并且应该符合您的代码编写规则:

error_code = FirstFunction();
if (error_code == 0) 
    error_code = SecondFunction();

if (error_code == 0) 
    error_code = ThirdFunction();

// etc...
return error_code;

【讨论】:

【参考方案2】:

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

int func(void)

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

    /* ... */

    return error_code;

【讨论】:

【参考方案3】:

精益和干净(like this one,但避免不喜欢的gotos):

int foo(void)

  int error_code;

  do 
    if (0 != (error_code = FirstFunction()))
    
      break;
    

    if (0 != (error_code = SecondFunction()))
    
      break;
    

    ...

   while (0);

  return error_code;

顺便说一句,这遵循更常见的模式: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;

【讨论】:

@AnttiHaapala:为什么?为什么这种事经常发生在我身上……: 可能是 1,3,7-三甲基黄嘌呤缺乏症 ;) 或者 Visual Basic 太多【参考方案4】:
if( (error_code = FirstFunction()) || (error_code = SecondFunction()) || ... )
   return error_code ; 


return error_code; //denoting no error.

这将只返回第一个返回非零的函数。这个想法是,对于if 语句,返回nonzero 的第一个函数将短路整个评估并从返回非零error_code 的函数返回error_code。另一件事是赋值语句的值是分配的值。这就是它起作用的原因。

更简单的方法是顺序 if-else

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

return error_code; 

【讨论】:

这很接近,我喜欢它在比较中捕获错误代码的方式,但 Benoit 的答案更接近我想要的。 注意:2 else 不是必需的。 @chux.: 你是说最后一个?早些时候我打错了电话FirstFunction 两次。你是这个意思吗? 不需要elses,因为当if条件失败时,return被执行;但是在第二个示例中,OP 问题的重点不是避免多个返回点吗? @DavidBowling.:已编辑。实际上我已经提供了 - 一个空白的if 也可以。【参考方案5】:

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

 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;

OK 是这些函数的成功返回值)

【讨论】:

我知道 OP 没有提到参数,但是,这种使用函数指针数组的方法仍然依赖于使用相同参数的所有函数,数量和类型相同。 确实我没想到。也许它可以用另一个参数数组来解决。但在这一点上,它可能不值得。【参考方案6】:

嗯,有一个用过的,例如在 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 将其安排为始终执行,但仍将其排除在外。)

真的,我认为您的第一个 sn-p 中的代码很好,问题在于您的指南。即使我们只在一处写return error_code;,也不足以保证保存在变量中的错误代码总是正确的,或者函数完成了所有可能需要的清理工作。 (考虑分配内存的东西,无论如何都必须释放它。)

【讨论】:

尽管我很想更改指南,但它们是我们客户整体项目要求的一部分,不在我的控制范围内。 是的,如果我尝试使用 goto,他们会解雇我:D

以上是关于第一次检测到错误后返回错误代码的主要内容,如果未能解决你的问题,请参考以下文章

第一章 错误处理

如何在cfcatch块中检查本机代码错误?

远程桌面提示:由于在客户端检测到一个协议错误(代码0x1104)……

SQL 错误“在批处理结束时检测到不可提交的事务”,数据库上没有事务

任务3

如何修复 ubuntu 中检测到系统程序错误的问题