【问题标题】:Use C switch statement for error handling使用 C switch 语句进行错误处理
【发布时间】:2009-06-10 12:54:07
【问题描述】:

考虑一下这个在实际工作之前检查错误的 C 结构:

int function(struct Context *context,struct Connection *conn)
{
    int retval;

    switch(0)
    {   
        case 0:
            retval = BUFFER_INACTIVE;
            if(conn->mSocket == -1) 
                break;
            retval = BUFFER_FULL;
            /* Is there enough room to add ? */
            if((context->mMaxBufferSize - conn->mSendPacketLength) < aPacketLength)
                break;

            /* Is the send packet buffer half sent? */
            if(conn->mSendPacketLength > 0 && conn->mSendPacketPos != conn->mSendPacket)
                break;

            /* Do some work here */
            retval = BUFFER_DONE;
    }
    /* Do some things before returning */
    printf("%d",retval);
    return retval;
}

您认为这是可读的吗?使用goto 或堆叠if() 的替代方案会更好吗?

【问题讨论】:

  • 我真的不怕 gotos...我对这个结构很抗拒,希望得到一些反馈。

标签: c error-handling goto


【解决方案1】:

我从未见过 switch 解决方案,但我做过这样的事情:

do {
    err = func();
    if( err ) break;
    err = func2();
    if( err ) break;
    ...
} while( 0 );
if( err ) {
   // handle errors
}

但那和这之间的真正区别是什么:

err = func();
if( err ) goto done;
err = func2();
if( err ) goto done;
...
done:
if( err ) {
   //handle errors;
}

第一个只是为了避免使用关键字goto 而重写的第二个,我认为goto 解决方案更具可读性。我花了一段时间,但我设法说服自己gotos 并不总是邪恶。

最后,如果可能的话,我更喜欢只使用if 语句,因为它使代码更具可读性,但如有必要,我更喜欢使用gotos。

【讨论】:

    【解决方案2】:

    我会说这不太可读。我认为使用 if 语句甚至 goto 将是一种更合适的方法。使用 goto 并不是世界末日,完全可以接受并适合错误处理。

    http://kerneltrap.org/node/553/2131

    【讨论】:

    • 我同意如果有人看到 switch(),需要一些时间来破译它的作用。
    【解决方案3】:

    我建议你使用 while(true) 而不是 switch:

    while(true)
    {   
                retval = BUFFER_INACTIVE;
                if(conn->mSocket == -1) 
                        break;
                retval = BUFFER_FULL;
                /* Is there enough room to add ? */
                if((context->mMaxBufferSize - conn->mSendPacketLength) < aPacketLength)
                        break;
    
                /* Is the send packet buffer half sent? */
                if(conn->mSendPacketLength > 0 && conn->mSendPacketPos != conn->mSendPacket)
                        break;
    
                /* Do some work here */
                retval = BUFFER_DONE;
                break;
    }
    

    【讨论】:

    • 我认为 while(true) 会导致某人期望循环,这绝对不会。使用“do { ... } while (0);”更地道。
    • 同意,做 { ... } while (0);是更好的方法。
    • 做 { ... while (0);也是在宏中包含范围的最佳实践...
    【解决方案4】:

    另一种选择是将其包装在一个函数中并返回而不是中断。这通常是一个坏主意,因为它最终添加了不必要的抽象层。但是,在某些情况下,它可以使事情变得更简单。

    【讨论】:

      【解决方案5】:

      另一种方法是使用级联 if:

      u8 u8IsOk;
      
      u8IsOk = Func1();
      
      if(u8IsOk)
      {
          /* Do some stuff...*/
          u8IsOk = Func2();
      } /* if */
      
      if(u8IsOk)
      {
          /* Do some stuff...*/
          u8IsOk = Func3();
      } /* if */
      

      ...等等。效率不如其他一些方法,但避免了过多的嵌套、goto、break、while(0) 和多次返回。

      【讨论】:

      • 我很惊讶人们似乎不喜欢它。这在嵌入式软件中很常见。
      猜你喜欢
      • 1970-01-01
      • 2021-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      • 2011-06-26
      • 2015-08-02
      相关资源
      最近更新 更多