Используйте оператор C switch для обработки ошибок - PullRequest
0 голосов
/ 10 июня 2009

Рассмотрим конструкцию 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()?

Ответы [ 5 ]

5 голосов
/ 10 июня 2009

Я никогда не видел решения для коммутатора, но я делал такие вещи:

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 более читабельно. Это заняло у меня некоторое время, но мне удалось убедить себя, что goto не всегда всегда зло.

В конце концов, я предпочитаю просто использовать операторы if, если это возможно, поскольку это делает код более читабельным, но goto s при необходимости.

4 голосов
/ 10 июня 2009

Я бы сказал, что это менее читабельно. Я думаю, что использование операторов if или даже goto было бы гораздо более подходящим подходом. Использование goto не является концом света и вполне приемлемо и подходит для обработки ошибок.

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

0 голосов
/ 10 июня 2009

Альтернативой является использование каскадных ifs:

u8 u8IsOk;

u8IsOk = Func1();

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

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

... и так далее. Не так эффективно, как некоторые другие методы, но позволяет избежать чрезмерного вложения, перехода, прерывания, while (0) и многократного возврата.

0 голосов
/ 10 июня 2009

Еще одна альтернатива - обернуть ее в функцию и вернуть вместо взлома. Это часто плохая идея, поскольку в итоге добавляется ненужный уровень абстракции. Однако в некоторых случаях это может упростить ситуацию.

0 голосов
/ 10 июня 2009

Я бы порекомендовал вам использовать 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;
}
...