C: Стиль кода для возврата ошибок? - PullRequest
0 голосов
/ 10 февраля 2012

Все мои функции выглядят так:

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;

все время?

Ответы [ 8 ]

7 голосов
/ 10 февраля 2012

Если использование короткозамкнутого ||, как предложено в другом ответе, не вариант, вы можете определить для этого макрос:

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

Тогда в вашем коде:

short Function()
{
  short ret;

  TRY(ret, FunctionA());
  TRY(ret, FunctionB());
  TRY(ret, FunctionC());

  return 0;
}

ПРИМЕЧАНИЕ : Вы должны быть очень осторожны при решении использовать макросы, но в этом случае я думаю, что может быть чистым способом решения проблемы. Следует отметить, однако, что эти утверждения скрывают тот факт, что функция может возвращаться рано в каждом из них. Если у вас есть дескрипторы открытых ресурсов (файловые дескрипторы, указатели на malloc ed данные, ...), они будут утечки. Вы и все, кто работает с кодом, должны знать об этом и использовать соответствующие процедуры обработки ошибок и очистки для более сложных случаев, чем этот.

5 голосов
/ 10 февраля 2012
short Function()
{
   short ret = 0;

   if(
       (ret = FunctionA()) != 0 ||
       (ret = FunctionB()) != 0 ||
       (ret = FunctionC()) != 0
     )
   {
      return ret;
   }

   return 0;
}
2 голосов
/ 10 февраля 2012

Я иду другим путем и показываю вам, как на самом деле я делаю это в программах, которые я пишу:

short Function() {
    short ret = 0;

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

На самом деле уменьшает код обработки ошибок в восходящем направлении, потому что хорошо написаноДиагностика лучше всего проводится на месте вызова.Конечно, это не меняет действия, которые должны быть предприняты в случае ошибки.

1 голос
/ 10 февраля 2012

Есть много способов переписать это, но я не могу придумать ничего более простого и понятного для глаз, чем у вас.
Вот еще один вариант, специально разработанный для минимизации количества 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;
0 голосов
/ 10 февраля 2012

Мне всегда нравились указатели функций.

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;
}
0 голосов
/ 10 февраля 2012
short Function() {

    short temp;

    return (temp = FunctionA()) ? temp : (temp = FunctionB()) ? temp : FunctionC();

}
0 голосов
/ 10 февраля 2012

Вы могли бы написать:

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

Вы, возможно, удивите некоторых из ваших коллег, хотя!

Альтернатива, использующая короткое замыкание, вдохновленное @Пост Тима:

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

В C ++ вы можете сказать:

if (short ret = FunctionA()) return ret;
0 голосов
/ 10 февраля 2012

Это должно быть эквивалентно, если я не ошибся

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

    }
   return ret;
}
...