Хороший стиль c при проверке большого количества возвращаемых значений

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

if(! (data = (big_struct *) malloc(sizeof(*data)))){
    //report allocation error
} else if(init_big_struct(data)){
    //handle initialization error
} else ...

Как вы, ребята, пишете такой код? Я проверил несколько руководств по стилям, но они больше интересуются переменными именами и пробелами.

Приветствуются ссылки на руководства по стилям.

Изменить: в случае, если это не ясно, я недоволен разборчивостью этого стиля и ищет что-то лучшее.

Ответ 2

Обычно я пишу этот код следующим образом:

data = (big_struct *) malloc(sizeof(*data));
if(!data){
    //report allocation error
    return ...;
}

err = init_big_struct(data);
if(err){
    //handle initialization error
    return ...;
}

...

Таким образом, я избегаю вызова функций внутри if и отладки проще, потому что вы можете проверить возвращаемые значения.

Ответ 3

Не используйте assert в производственном коде.
В режиме отладки assert никогда не следует использовать для чего-то, что действительно может произойти (например, malloc return NULL), скорее оно должно использоваться в невозможных случаях (например, индекс массива выходит за пределы в C)

Прочитайте это сообщение для более.

Ответ 4

Одним из методов, который я использовал для большого эффекта, является тот, который используется В. Ричардом Стивенсом в Unix Network Programming (код доступен для загрузки здесь. Для обычных функций, которые он ожидает добиться успеха все время, и не имеет возможности для отказа, он обертывает их, используя заглавную букву (код сжатый по вертикали):

void * Malloc(size_t size) {
    void    *ptr;
    if ( (ptr = malloc(size)) == NULL)
        err_sys("malloc error");
    return(ptr);
}

err_sys здесь отображается ошибка, а затем выполняется exit(1). Таким образом, вы можете просто позвонить Malloc и знать, что он будет ошибочно, если есть проблема.

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

Ответ 5

Я склонен к

  • Делегирование проверки ошибок на функции обертки (например, Stevens)
  • При ошибке имитируйте исключения с помощью longjmp. (Я действительно использую Dave Hanson C Интерфейсы и реализации для имитации исключений.)

Другой вариант - использовать Don Knuth грамотное программирование для управления кодом обработки ошибок или каким-либо другим препроцессором. Этот параметр доступен, только если вы установили правила для своего магазина: -)

Ответ 6

Единственное свойство группировки кода, подобное этому, состоит в том, что существует просто внешняя последовательность, которой она должна следовать. Вот почему вы помещаете эти распределения в одну функцию, но это очень слабая общность. Почему некоторые люди рекомендуют отказаться от преимуществ области вложенности, если это выходит за рамки моего понимания. Вы действительно пытаетесь помассировать помаду на свиньи (никакого оскорбления) - природа кода никогда не даст ничего чистого, лучше всего использовать компиляторы, чтобы улавливать (поддерживать) ошибки. Придерживайтесь, если ИМХО.

PS: если я еще не убедил вас: как будет выглядеть goto-решение, если вам нужно принять тройные решения? Если это будет уродливо, но goto's