【问题标题】:C: Code style for returning errors?C:返回错误的代码风格?
【发布时间】:2012-03-02 08:10:15
【问题描述】:

我所有的函数都是这样的:

short Function()
{
   short ret = 0;

   ret = FunctionA();   
   if(ret != 0) return ret;

   ret = FunctionB();
   if(ret != 0) return ret;

   ret = FunctionC();
   if(ret != 0) return ret;

   return 0;
}

有没有更好的方法来写这个?无需重复

if(ret != 0) return ret;

一直?

【问题讨论】:

    标签: c error-handling styles return-value


    【解决方案1】:

    如果不能像其他答案中建议的那样使用短路的||,您可以为此定义一个宏:

    #define TRY(var, x) if ((var = (x))) return var
    

    然后在你的代码中:

    short Function()
    {
      short ret;
    
      TRY(ret, FunctionA());
      TRY(ret, FunctionB());
      TRY(ret, FunctionC());
    
      return 0;
    }
    

    注意:在决定使用宏时应该非常小心,但在这种情况下,我认为它可能是解决问题的一种干净的方法。 但是,必须提到的是,这些语句隐含了这样一个事实,即函数可以在每个语句中提前返回。如果您有打开的资源句柄(文件描述符、指向malloced 数据的指针……),它们就会泄漏。您和使用该代码的每个人都应该意识到这一点,并在比这更复杂的情况下使用适当的错误处理和清理例程。

    【讨论】:

    • 宏的使用非常酷,从来不知道你可以在宏中使用 if 语句。
    • do { ret = (x); if (ret != 0) return ret; } while (0) 是更好的选择!
    • 然后交给n00b维护:(
    • @Marlon:我知道这种结构,但我不确定它在这种情况下如何适用。你会遇到同样的问题,只是如果发生错误,你必须break 而不是return
    • @The Elite Noob:这是我真正使用宏的极少数情况之一,因为它让我的生活变得如此轻松(或者可能是因为我只是不知道如何正确地做到这一点: )
    【解决方案2】:
    short Function()
    {
       short ret = 0;
    
       if(
           (ret = FunctionA()) != 0 ||
           (ret = FunctionB()) != 0 ||
           (ret = FunctionC()) != 0
         )
       {
          return ret;
       }
    
       return 0;
    }
    

    【讨论】:

    • +1 我投票给这个——在宏中隐藏返回语句和变量名(另一个答案)是我不想处理的代码。
    • @Justin:嗯,如果在代码库中正确且一致地使用它,它会非常干净和方便,恕我直言。在你的脑海中保留这一件事(使用那个宏来传播子函数中的错误)并不是特别苛刻。
    • @MrLister:是的,抱歉 - 已删除!
    • @NiklasB。那么在处理其他人的宏时,您的体验要比我好得多:)
    • @Justin:我非常怀疑这一点。也许你有道理。尽管如此,我认为错误处理确实是一个适当使用宏可以节省大量重复代码的地方(前提是团队中的每个人都遵循一致的约定)。
    【解决方案3】:

    我将走另一条路,向您展示我在编写的程序中实际上是如何做到这一点的:

    short Function() {
        short ret = 0;
    
        ret = FunctionA();
        if(ret != 0) {
            SomeUsefulMessageOrAssertionHere();
            return ret;
        }
        ...
    

    它实际上减少上游错误处理代码,因为编写良好的诊断最好在调用点处理。当然,它不会改变发生错误时必须采取的措施。

    【讨论】:

      【解决方案4】:

      有很多方法可以重写这个,但我想不出比你的更直接和更容易的方法了。
      这是另一个变体,专门设计用于最大限度地减少 if ... return 语句的数量。

      int i;
      for (i = 0; i<3; +i) {
         switch (i) {
            case 0: ret = FunctionA(); break;
            case 1: ret = FunctionB(); break;
            case 2: ret = FunctionC(); break;
         }
         if (ret != 0) return ret;
      }
      return 0;
      

      【讨论】:

      • 好吧,一方面,这可以让您进行一些优化,因为您可以在找到正确答案之前计算循环运行了多少次。假设FunctionB比FunctionA更经常正确,那么你可以把FunctionB放在第一位。除此之外,这只是原始问题的另一个变体。
      【解决方案5】:

      如果我没记错的话应该是等价的

      short Function()
      {
         short ret = FunctionA();   
         if(ret == 0)
         {
              ret = FunctionB();
              if(ret == 0)
              {
                  ret = FunctionC();
              }
      
          }
         return ret;
      }
      

      【讨论】:

        【解决方案6】:
        short Function() {
        
            short temp;
        
            return (temp = FunctionA()) ? temp : (temp = FunctionB()) ? temp : FunctionC();
        
        }
        

        【讨论】:

          【解决方案7】:

          你可以写:

          short ret;
          if (ret = FunctionA()) return ret;
          if (ret = FunctionB()) return ret;
          if (ret = FunctionC()) return ret;
          

          不过,你可能会让一些同事大吃一惊!

          另一种使用短路的方法,灵感来自@Tim 的帖子:

          short ret;
          return (ret = FunctionA()) || (ret = FunctionB()) || (ret = FunctionC()) ? ret : 0;
          

          在 C++ 中你可以说:

          if (short ret = FunctionA()) return ret;
          

          【讨论】:

          • 返回带||运算符不起作用,因为它返回 1 或 0,而不是 ret。不过你可以写return (ret = FunctionA()) || (ret = FunctionB()) || (ret = FunctionC()) ? ret :0;
          • @MrLister:确实,谢谢。不过,我想强调的是,您在任何情况下都会返回 ret
          • 好的,这可能是正确的做法。不过看起来确实有点傻,抱歉……
          【解决方案8】:

          我自己一直很喜欢函数指针。

          int main()
          {
              typedef ret-type (*Fptr)( ... args-types ... );
          
              const int N_FUNC = 3;
              Fptr functions[] = { FunctionA, FunctionB, FunctionC };
          
              short ret = 0;
              for( int i=0; ! ret && i < N_FUNCS; i++ )
                  ret = functions[i];
          
              return ret;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-04-03
            • 1970-01-01
            • 2011-12-04
            • 2014-07-03
            • 1970-01-01
            • 2022-11-07
            • 2013-02-20
            • 1970-01-01
            相关资源
            最近更新 更多