2013-02-27 5 views
1

Предположим, что я хочу написать игру (на C), которая спросит пользователя, хочет ли он снова играть после окончания игры.Является ли это приемлемым способом использования goto?

Я вижу два очевидных способа написать это.

Первое:

int main(void) 
{ 
    /* variable declarations and initializations */ 

    do { /* optionally multiple games */ 

     /* game code here */ 
     ........ 

     /* prompt user wheter he wants to play again */ 
     bool playagain = playagain(); 

    } while(playagain); 

    ..... 
} 

И второе:

int main(void) 
{ 
    /* variable declarations and initializations */ 

game_start: /* optionally multiple games */ 

    /* game code here */ 
    ........ 

    /* prompt user wheter he wants to play again */ 
    bool playagain = playagain(); 

    if (playagain) 
     goto game_start; 

    ..... 
} 

Я знаю, что в целом это плохая идея использовать GOTO заявления, но я думаю, что здесь это делает код более понятным и спасает нас от дополнительный уровень отступа.

Так что, мой вопрос в том, является ли этот конкретный пример надлежащим способом использования инструкции goto или я должен его избегать?

+2

Я думаю, что проблема людей с goto не использует 1 goto, это когда она вырастает до 10 или 100. С циклом вы четко видите область действия, с goto это может быть где угодно. – dutt

+1

Это вопрос вкуса. Я не вижу ничего плохого в использовании goto вообще. Почему это было бы плохо? – Art

+0

Плохо, когда вы начнете использовать их много. – LtWorf

ответ

2

После более чем 40 лет дебатирования Гото, до сих пор нет единого мнения среди всех программистов в мире.

Наиболее распространенное мнение (?) Заключается в том, что goto в порядке, в редких случаях, и в таких случаях его следует использовать только для того, чтобы прыгать вниз. Один из таких примеров - это разрыв нескольких проверенных циклов или операторов. Другим примером является обработка ошибок, когда вы переходите к метке в конце функции, «обработка исключений для несовершеннолетних».

Некоторые люди считают, что goto considered harmful и никогда не будет использоваться ни при каких обстоятельствах, поскольку ключевое слово goto всегда может быть заменено другими языковыми механизмами.

Лично я предпочитаю никогда не использовать Гото, главным образом, чтобы избежать дискуссий, но вместо этого я использую очень похожую конструкцию, с функциями:

int main() 
{ 
    while (play_a_game()) 
    ; 
} 

bool play_a_game (void) 
{ 
    game();  

    return play_again(); 
} 

Кроме того, вы можете выйти из нескольких циклов, используя оператор возврата из функция, а не goto. По иронии судьбы, программисты C редко имеют проблемы с возвратами функций или операторами break, но они видят красный, когда появляется goto, хотя полученный машинный код, скорее всего, будет таким же.

Как правило, когда вы беспокоитесь о нескольких слоях отступа, делая код нечитаемым, функции всегда являются решением.

4

Как правило, люди, использующие случаи ненависти к Н, потому что они видят, что «уйти от необходимости получить» являются одной из причин использования С для начала.

Как только вы решите, что хотите использовать gotos, продолжайте использовать их. Однако в целом это приводит к запутыванию кода, что вам будет сложно задавать вопросы о переполнении стека.

Я бы полностью избежал переселений.

Фактически, единственная причина, по которой я использую gotos, - это когда я хочу написать программу на C перед написанием программы назначения, которая должна быть записана в сборке (что намного проще визуализировать с помощью gotos).

В любом случае, если вы чувствуете, что есть преимущества использования gotos над «нормальными» инструкциями по контролю, продолжайте использовать их. Но будьте осторожны, там будут драконы.

+0

Я думаю, что дело в том, что когда вы находите место для использования goto, часто есть более чистое решение, которое его не требует. Такие, как глубоко вложенный код. goto - это приемлемый способ выхода из глубоко вложенных циклов, но часто вы можете заменить петли чем-то немного чище. Смотрите: http://c2.com/cgi/wiki?GotoConsideredHarmful –

+0

Правильно, я настаивал на том, что основная цель высокоуровневых языков программирования, таких как fortran и C, заключалась в создании контрольных операторов, таких как if и else и еще, если и петли и другие забавные вещи, чтобы избежать необходимости прыгать по коду, как сумасшедший, пытающийся следить за потоком программы. – Dmitry

+1

Er, C является одним из немногих распространенных языков, где 'goto' по-прежнему широко используется. Люди, которые хотят прекратить использование 'goto', перестают использовать C и начинают использовать языки с поддержкой исключений. –

6

Это не лучший пример, в K & R вы можете найти хороший один:

C обеспечивает бесконечно abusable о Гото и метки к ответвлением. Формально утверждение goto никогда не требуется, и в практике практически всегда легко писать код без него. У нас не используется goto в этой книге. Тем не менее, есть несколько ситуаций , где gotos могут найти место. Наиболее распространенным является отказ от обработки в некоторой глубоко вложенной структуре, такой как разрыв двух или более петель сразу. Оператор break не может использоваться напрямую, так как он только выходит из самого внутреннего цикла. Таким образом:

  for (...) 
       for (...) { 
        ... 
        if (disaster) 
         goto error; 
       } 
     ... 
    error: 
     /* clean up the mess */ 

Эта организация удобна, если код обработки ошибок нетривиален, и если ошибки могут возникать в нескольких местах.

+2

Это законный пример, но IMO - лучшее решение для написания вложенного цикла в отдельной функции и использования оператора return , или использовать блоки try-catch (не относящиеся к C) –

+0

@MarkusUnterwaditzer, я согласен –

+1

@MarkusUnterwaditzer Поскольку C не имеет исключений, это конкретное использование 'goto' может быть лучшим способом решения некоторых проблем. Естественно, было бы лучше использовать исключения, но если язык их не поддерживает, это не очень конструктивный комментарий. –

4

В вашем втором примере вы в основном пишете цикл, но вместо того, чтобы использовать одну из существующих и хорошо известных конструкций контуров, вы используете if + goto.

Я бы сказал, что 1-й уровень гораздо понятнее.

3

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

0

Я использую его очень редко, как способ «финализировать».

fun() { 
    d = getDatabaseConnection(...); 
    if (d) { 
    f = fopen(...); 
    if (f) { 
     ...do things... 
     if (error(...)) { 
     goto finalize; 
     } 
     ...do more things... 
    } 
    } 

    finalize: 
    if (f) fclose(f); 
    if (d) closeDatabaseConnection(d); 
}   
+0

'if (a) free (a);' можно безопасно заменить на 'free (a)'. – Lundin

+0

ОК, я меняю код ... –

+0

Нет необходимости ничего менять :) В скобках, не имеющих никакого отношения к исходному вопросу, я просто хотел указать, что передача NULL в free() безопасна. – Lundin

Смежные вопросы