C: Вложенные Ifs или Gotos - PullRequest
9 голосов
/ 10 ноября 2010

Каков наилучший способ управления ресурсами для программы C .Должен ли я использовать вложенную структуру if или использовать операторы goto?

Я знаю, что существует много табу о goto утверждениях.Тем не менее, я думаю, что это оправдано для очистки местного ресурса.Я предоставил два образца.Один сравнивает вложенную структуру if, а другой использует операторы goto.Лично я нахожу, что операторы goto облегчают чтение кода.Для тех, кто может утверждать, что вложено, если предлагает лучшую структуру, представьте, что тип данных был чем-то отличным от char *, например дескриптор Windows.Я чувствую, что вложенная структура , если выйдет из-под контроля с рядом функций CreateFile или любой другой функцией, которая принимает большое количество параметров.

Эта статья демонстрирует, что локальные операторы goto создают RAII для кода C.Код аккуратный, легко следовать.Представьте, что это серия из вложенных, если операторов.

Я понимаю, что goto является табу во многих других языках, потому что существуют другие механизмы управления, такие как try / catch и т. Д., Однако, в C это представляется целесообразным.

#include <stdlib.h>

#define STRING_MAX 10

void gotoExample()
{
    char *string1, *string2, *string3, *string4, *string5;

    if ( !(string1 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto gotoExample_string1;
    if ( !(string2 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto gotoExample_string2;
    if ( !(string3 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto gotoExample_string3;
    if ( !(string4 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto gotoExample_string4;
    if ( !(string5 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto gotoExample_string5;

    //important code goes here

gotoExample_string5:
    free(string4);
gotoExample_string4:
    free(string3);
gotoExample_string3:
    free(string2);
gotoExample_string2:
    free(string1);
gotoExample_string1:
}

void nestedIfExample()
{
    char *string1, *string2, *string3, *string4, *string5;

    if (string1 = (char*) calloc(STRING_MAX, sizeof(char))) 
    {
        if (string2 = (char*) calloc(STRING_MAX, sizeof(char)))
        {
            if (string3 = (char*) calloc(STRING_MAX, sizeof(char)))
            {
                if (string4 = (char*) calloc(STRING_MAX, sizeof(char)))
                {
                    if (string5 = (char*) calloc(STRING_MAX, sizeof(char)))
                    {
                        //important code here
                        free(string5);
                    }
                    free(string4);
                }
                free(string3);
            }
            free(string2);
        }
        free(string1);
    }
}


int main(int argc, char* argv[])
{
    nestedIfExample();
    gotoExample();
    return 0;
}

Я также хотел бы процитировать Линуса Торвальдса о goto инструкциях внутри Linux Kernel .

И иногда структура плохая ,и встает на пути, и использование «goto» просто намного понятнее.

Например, довольно часто встречаются условные выражения, которые НЕ ГНЕЗДАЮТСЯ.

В этом случае у вас есть двавозможности

  • используйте goto и будьте счастливы, так как это не требует вложенности

    Это делает код более читабельным, поскольку код простовыполняет то, что говорит алгоритм:

  • продублируйте код и перепишите его во вложенной форме, чтобы вы могли
    использовать структурированные переходы.

    Это часто делает код намного МЕНЬШЕ читаемым, сложнее в обслуживании и больше.

Язык Паскаль является ярким примером последней проблемы.Поскольку в нем нет оператора «break», циклы в (традиционном) Pascal часто выглядят как полное дерьмо, потому что вы должны добавить совершенно произвольную логику, чтобы сказать «Я закончил сейчас».

Приемлемо ли goto для управления ресурсами?Должен ли я использовать вложенных, если операторов или есть лучший способ?

Обновление: Примеры хороших Gotos In C

Ответы [ 11 ]

0 голосов
/ 30 ноября 2010

Для меня я предпочитаю этот стиль обработки ошибок goto. Взяв фрагмент кода Ника Д. на шаг вперед, он использует одну общую метку goto для обработки ошибок.

void gotoExample()
{
    char *string1, *string2, *string3, *string4, *string5;
    string1 = string2 = string3 = string4 = string5 = NULL;

    if ( !(string1 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto HANDLE_ERROR;
    if ( !(string2 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto HANDLE_ERROR;
    if ( !(string3 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto HANDLE_ERROR;
    if ( !(string4 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto HANDLE_ERROR;
    if ( !(string5 = (char*) calloc(STRING_MAX, sizeof(char))) )
        goto HANDLE_ERROR;

    //important code goes here


HANDLE_ERROR:
  if (string5)
    free(string5);

  if (string4)
    free(string4);

  if (string3)
    free(string3);

  if (string2)
    free(string2);

  if (string1)
    free(string1);

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...