GOTO по-прежнему считается вредным?

Все знают о Dijkstra Письма в редакцию: перейдите к заявлению, которое считается вредным (также здесь.html расшифровка и здесь.pdf), и с того времени был ужасный толчок, чтобы избежать ответа когда это возможно. Хотя можно использовать goto для создания недостижимого, растягивающегося кода, он тем не менее остается в современных языках программирования. Даже усовершенствованная структура управления continuation в Схеме может быть описана как сложная версия.

Какие обстоятельства требуют использования goto? Когда лучше избегать?

В качестве дополнительного вопроса: C предоставляет пару функций, setjmp и longjmp, которые обеспечивают возможность перехода не только в текущий кадр стека, но и в любой из вызывающих кадров. Должны ли они считаться опасными, как goto? Более опасно?


Сам Дийкстра сожалел об этом титуле, за который он не был ответственным. В конце EWD1308 (также здесь.pdf ) он написал:

Наконец, рассказ для записи. В 1968 году связь ACM опубликовал текст моего доклада под название "Утверждение goto вредных", которые в последующие годы чаще всего ссылаются, к сожалению, часто авторами который больше не видел этого, чем его название, которое стало краеугольным камнем моя слава, став шаблоном: мы будут видеть все виды статей в название "Х считается вредным" для почти любой X, в том числе один под названием "Дейкстра считалась вредной". Но что произошло? Я представил документ под заголовком " Дело против утверждение goto", которое, чтобы для ускорения его публикации, редактор превратился в "письмо в редактор", и в этом процессе он учитывая его новое название изобретение! Редактором был Никлаус Вирт.

Хорошо продуманная классическая статья об этой теме, соответствующая значению Дийкстры, Структурированное программирование с переходом к заявлениям, Дональдом Э. Кнут. Чтение обоих помогает восстановить контекст и не догматическое понимание предмета. В этой статье высказывается мнение Дейкстры об этом случае и еще сильнее:

Дональд Э. Кнут: Я считаю, что, представив такой Я не на самом деле не согласен резко с идеями Дейкстры, поскольку он недавно написал следующее: "Пожалуйста, не попадайте в ловушку полагая, что я ужасно догматический [о выражение]. У меня неудобно чувствуя, что другие делают религия из него, как будто концептуальные проблемы программирования может быть решена одним трюком, путем простая форма кодирования!"

Ответ 1

Следующие утверждения являются обобщениями; в то время как всегда можно просить об исключении, обычно (по моему опыту и скромному мнению) не стоит риска.

  • Непринужденное использование адресов памяти (GOTO или raw указателей) предоставляет слишком много возможностей для легко избежать ошибок.
  • Чем больше способов добраться до определенного "местоположения" в коде, тем менее уверенным может быть то, что состояние системы в этой точке. (См. Ниже.)
  • Структурированное программирование ИМХО меньше об "избегании GOTO" и больше о том, как структура кода соответствует структуре данных. Например, повторяющаяся структура данных (например, массив, последовательный файл и т.д.), Естественно, обрабатывается повторяющейся единицей кода. Наличие встроенных структур (например, while, for, until, for-each и т.д.) Позволяет программисту избегать скуки повторения тех же шаблонов кода cliched.
  • Даже если GOTO является детализацией реализации на низком уровне (не всегда в случае!), он ниже уровня, о котором программист должен думать. Сколько программистов балансирует свои личные чековые книжки в сырых двоичных файлах? Сколько программистов беспокоиться о том, какой сектор на диске содержит определенную запись, а не просто предоставить ключ к движку базы данных (и как многие способы могут пойти не так, если мы действительно написали все наши программы с точки зрения секторов физического диска)?

Сноски к вышесказанному:

В отношении точки 2 рассмотрим следующий код:

a = b + 1
/* do something with a */

В пункте "сделать что-то" в коде мы можем с большой уверенностью заявить, что a больше, чем b. (Да, я игнорирую возможность прерывания целочисленного переполнения. Не пропустите простой пример.)

С другой стороны, если код читал так:

...
goto 10
...
a = b + 1
10: /* do something with a */
...
goto 10
...

Множество способов получить метку 10 означает, что нам нужно работать намного сложнее, чтобы быть уверенными в отношениях между a и b в этой точке. (На самом деле, в общем случае он не подлежит определению!)

Что касается пункта 4, то все понятие "что-то происходит" в коде - это просто метафора. Ничто на самом деле "не происходит" внутри ЦП, кроме электронов и фотонов (для отработанного тепла). Иногда мы бросаем метафору для другого, более полезного, одного. Я помню, как встречался (несколько десятилетий назад!) Язык, на котором

if (some condition) {
  action-1
} else {
  action-2
}

был реализован на виртуальной машине, скомпилировав action-1 и action-2 как безрежимные подпрограммы без параметров, а затем используя один код аргумента VM с двумя аргументами, который использовал логическое значение условия для вызова того или иного, Концепция была просто "выбрать, что вызывать сейчас", а не "идти сюда или идти туда". Опять же, просто изменение метафоры.

Ответ 2

XKCD's GOTO Comic

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

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

Ответ 3

Иногда полезно использовать GOTO в качестве альтернативы обработке исключений в рамках одной функции:

if (f() == false) goto err_cleanup;
if (g() == false) goto err_cleanup;
if (h() == false) goto err_cleanup;

return;

err_cleanup:
...

COM-код, похоже, довольно часто попадает в этот шаблон.

Ответ 4

Я могу вспомнить только один раз. У меня была серия из пяти вложенных счетных циклов, и мне нужно было вырваться из всей структуры изнутри рано, основываясь на определенных условиях:

for{
  for{
    for{
      for{
        for{
          if(stuff){
            GOTO ENDOFLOOPS;
          }
        }
      }
    }
  }
}

ENDOFLOOPS:

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

Никакие велосирапторы не напали на меня.

Ответ 5

У нас уже было это обсуждение, и я поддерживаю мой пункт.

Кроме того, мне надоели люди, описывающие языковые структуры более высокого уровня как "goto в маскировке", потому что они явно не имеют смысла вообще. Например:

Даже расширенная структура управления продолжением в Схеме может быть описана как сложная версия goto.

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

Аналогично, говоря: "GOTO - это инструмент, и поскольку все инструменты, которые он может использовать и злоупотреблять", совершенно не имеют значения. Ни один современный строитель не будет использовать скалу и утверждать, что это "инструмент". Скалы были заменены молотками. goto был заменен структурами управления. Если бы строитель был застрял в дикой природе без молотка, он, конечно же, использовал бы камень. Если программист должен использовать более низкий язык программирования, который не имеет функции X, ну, конечно, ей, возможно, придется использовать goto. Но если она использует его где-нибудь еще вместо подходящей языковой функции, она явно не правильно поняла язык и неправильно использует его. Это действительно так просто.

Ответ 6

Goto крайне низок в моем списке вещей для включения в программу только ради этого. Это не означает, что это неприемлемо.

Готово для государственных машин. Оператор switch в цикле (в порядке типичного значения): (a) фактически не представляет поток управления, (b) уродливый, (c) потенциально неэффективен в зависимости от языка и компилятора. Таким образом, вы в конечном итоге пишете одну функцию для каждого состояния и делаете такие вещи, как "return NEXT_STATE;" которые даже выглядят как goto.

Конечно, сложно закодировать государственные машины таким образом, чтобы их было легко понять. Однако ни одна из этих трудностей не связана с использованием goto, и ничто из этого не может быть уменьшено за счет использования альтернативных структур управления. Если ваш язык не имеет конструкцию "state machine". Мой не делает.

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

setjmp/longjmp может быть приятным для реализации исключений или поведения, подобного исключению. Несмотря на то, что не повсеместно оцениваются, исключения обычно считаются "действующей" структурой управления.

setjmp/longjmp "более опасны", чем goto, в том смысле, что их труднее использовать правильно, не говоря уже о понятном.

Там никогда не было и не будет когда-либо, любой язык, на котором он наименее сложно писать плохо код. - Дональд Кнут.

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

Затем это будет "указатели считаются вредными", а затем "утиная типизация считается вредной". Тогда кто останется защищать вас, когда они придут забрать вашу небезопасную конструкцию программирования? А?

Ответ 7

В Linux: используя goto In Kernel Code на Kernel Trap, там обсуждается с Линусом Торвальдсом и "новым парнем" об использовании GOTO в коде Linux. Там есть очень хорошие моменты, и Линус одет в это обычное высокомерие:)

Некоторые отрывки:

Линус: "Нет, тебе промыли мозги Люди CS, которые думали, что Никлаус Вирт действительно знал, что он говоря о. Он этого не сделал. Он не есть подсказка."

-

Линус: "Я думаю, что это хорошо, и они часто более читабельны, чем большое количество отступов."

-

Линус: "Конечно, в глупых языках как Pascal, где метки не могут быть дескриптивный, goto может быть плохим".

Ответ 8

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

Я считаю, что опасность goto в C сильно преувеличена. Помните, что исходные аргументы goto имели место во времена языков, таких как старомодный BASIC, где новички записывали код спагетти следующим образом:

3420 IF A > 2 THEN GOTO 1430

Здесь Linus описывает подходящее использование goto: http://www.kernel.org/doc/Documentation/CodingStyle (глава 7).

Ответ 9

Сегодня трудно увидеть большое дело в заявлении GOTO, потому что люди с "структурированным программированием" в основном выиграли дискуссию, и сегодня языки имеют достаточные структуры потока управления, чтобы избежать GOTO.

Подсчитайте количество GOTO в современной программе на C. Теперь добавьте количество операторов break, continue и return. Кроме того, добавьте количество раз, когда вы используете if, else, while, switch или case. Это о том, сколько GOTO вашей программы было бы, если бы вы писали в FORTRAN или BASIC в 1968 году, когда Дейкстра написал свое письмо.

Языки программирования в то время отсутствовали в потоке управления. Например, в оригинальном Dartmouth BASIC:

  • Операторы
  • if не имели else. Если вы этого хотели, вам пришлось написать:

    100 IF NOT condition THEN GOTO 200
    ...stuff to do if condition is true...
    190 GOTO 300
    200 REM else
    ...stuff to do if condition is false...
    300 REM end if
    
  • Даже если ваш оператор if не нуждался в else, он все еще ограничивался одной строкой, которая обычно состояла из GOTO.

  • Не было оператора DO...LOOP. Для циклов без FOR вам нужно было закончить цикл с явным GOTO или IF...GOTO назад к началу.

  • Не было SELECT CASE. Вы должны были использовать ON...GOTO.

Итак, вы закончили с большим количеством GOTO в своей программе. И вы не могли зависеть от ограничения GOTO с одной подпрограммой (потому что GOSUB...RETURN был такой слабой концепцией подпрограмм), поэтому эти GOTO могли идти куда угодно. Очевидно, что это затрудняет контроль потока.

Здесь происходит движение анти- GOTO.

Ответ 10

В некоторых случаях Go To может предоставить своего рода резерв для "реальной" обработки исключений. Рассмотрим:

ptr = malloc(size);
if (!ptr) goto label_fail;
bytes_in = read(f_in,ptr,size);
if (bytes_in=<0) goto label_fail;
bytes_out = write(f_out,ptr,bytes_in);
if (bytes_out != bytes_in) goto label_fail;

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

success=false;
do {
    ptr = malloc(size);
    if (!ptr) break;
    bytes_in = read(f_in,ptr,size);
    if (count=<0) break;
    bytes_out = write(f_out,ptr,bytes_in);
    if (bytes_out != bytes_in) break;
    success = true;
} while (false);

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

Итак, мораль истории - если вы прибегаете к чему-то действительно глупому, чтобы избежать использования goto, тогда не делайте этого.

Ответ 11

Дональд Э. Кнут ответил на этот вопрос в книге "Грамотное программирование", 1992 CSLI. На стр. 17 есть эссе " Структурированное программирование с операторами goto" (PDF). Я думаю, что статья могла быть опубликована и в других книгах.

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

В статье содержится полное описание проблемы, примеры истории, примеры и встречные примеры.

Ответ 12

Привлеченный Джеем Баллоу, добавившим ответ, я добавлю свои £ 0,02. Если бы Бруно Раншарт еще не сделал этого, я бы упомянул статью Кнута "Структурированное программирование с инструкциями GOTO".

Одна вещь, которую я не видел, обсуждалась, это своего рода код, который, хотя и не совсем распространенный, преподавался в фортранских учебниках. Такие вещи, как расширенный диапазон цикла DO и подпрограммы с открытым кодом (помните, это будет Fortran II, или Fortran IV, или Fortran 66, а не Fortran 77 или 90). Есть хотя бы шанс, что синтаксические детали неточны, но понятия должны быть достаточно точными. Фрагменты в каждом случае находятся внутри одной функции.

Обратите внимание, что в превосходной, но устаревшей (и не издаваемой) книге " Элементы стиля программирования, 2nd Edn " Kernighan & Plauger содержатся некоторые реальные примеры злоупотребления GOTO из учебников по программированию его эпохи (конец 70-х годов). Однако материал ниже не из этой книги.

Расширенный диапазон для циклы DO

       do 10 i = 1,30
           ...blah...
           ...blah...
           if (k.gt.4) goto 37
91         ...blah...
           ...blah...
10     continue
       ...blah...
       return
37     ...some computation...
       goto 91

Одной из причин такой ерунды была старая старомодная перфокарта. Вы можете заметить, что метки (красиво не по порядку, потому что это был канонический стиль!) Находятся в столбце 1 (фактически, они должны быть в столбцах 1-5), а код - в столбцах 7-72 (столбец 6 был продолжением). колонка маркера). Столбцам 73-80 будет присвоен порядковый номер, и существуют машины, которые сортируют колоды перфокарт в порядке порядкового номера. Если ваша программа работала с последовательными карточками и вам нужно было добавить несколько карточек (строк) в середину цикла, вам пришлось бы перевыпускать все после этих дополнительных строк. Однако, если вы заменили одну карту на GOTO, вы можете избежать повторного упорядочения всех карт - вы просто подсовываете новые карты в конце процедуры с новыми порядковыми номерами. Считайте, что это первая попытка "зеленых вычислений" - экономия перфокарт (или, более конкретно, экономия при перепечатывании рабочей силы и сохранение ошибок повторного ввода).

О, вы также можете заметить, что я обманываю, а не кричу - Фортран IV был написан в верхнем регистре как обычно.

Открытая подпрограмма

       ...blah...
       i = 1
       goto 76
123    ...blah...
       ...blah...
       i = 2
       goto 76
79     ...blah...
       ...blah...
       goto 54
       ...blah...
12     continue
       return
76     ...calculate something...
       ...blah...
       goto (123, 79) i
54     ...more calculation...
       goto 12

GOTO между метками 76 и 54 является версией вычисленного goto. Если переменная я имеет значение 1, перейдите к первой метке в списке (123); если оно имеет значение 2, перейдите ко второму и так далее. Фрагмент от 76 до вычисленного goto является подпрограммой с открытым кодом. Это был кусок кода, выполненный скорее как подпрограмма, но записанный в теле функции. (У Fortran также были операторные функции - встроенные функции, которые помещались в одну строку.)

Существовали худшие конструкции, чем вычисленное goto - вы могли назначать метки переменным, а затем использовать назначенное goto. Googling назначил goto, чтобы сообщить мне, что он был удален из Фортрана 95. Примите участие в революции структурного программирования, которая, можно честно сказать, началась публично с письмом или статьей Дейкстры "GOTO рассмотрен вредно".

Без некоторого знания того, что было сделано в Фортране (и на других языках, большинство из которых по праву попали на обочину), нам, новичкам, трудно понять масштаб проблемы, с которой сталкивался Дейкстра. Черт, я начал программировать только через десять лет после того, как это письмо было опубликовано (но у меня действительно было несчастье программировать на Фортране IV некоторое время).

Ответ 13

Нет таких вещей, которые GOTO считали вредными.

GOTO - это инструмент, и, как и все инструменты, его можно использовать и злоупотреблять.

Однако в мире программирования есть много инструментов, которые склонны к злоупотреблениям больше, чем к использованию, и GOTO является одним из них. оператор WITH Delphi является другим.

Лично я не использую ни в типичном коде, но у меня было странное использование как GOTO, так и WITH, которые были гарантированы, а альтернативное решение содержало бы больше кода.

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

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

Ответ 14

Перейти к рассмотрению полезно.

Я начал программировать в 1975 году. Программистам эпохи 1970-х годов слова "goto считаются вредными" говорили более или менее о том, что стоит использовать новые языки программирования с современными структурами управления. Мы пробовали новые языки. Мы быстро обратились. Мы никогда не возвращались.

Мы никогда не возвращались, но, если вы моложе, тогда вы никогда не были там в первую очередь.

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

Лозунги, которые не понимают, не очень освещают. Вероятно, лучше всего забыть такие лозунги. Такие лозунги не помогают.

Этот конкретный лозунг, однако, "Goto считается вредным", взял на себя жизнь нежити.

Можно ли не злоупотреблять? Ответ: конечно, но так что? Практически каждый элемент программирования можно злоупотреблять. Смиренный bool, например, злоупотребляет чаще, чем некоторые из нас хотели бы поверить.

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

Самая большая проблема с goto, вероятно, не техническая, а социальная. Программисты, которые не очень много знают, иногда чувствуют, что устаревшее goto делает их разумными. Возможно, вам придется время от времени удовлетворять таких программистов. Такова жизнь.

Самое худшее в сегодняшнем случае - это то, что он недостаточно используется.

Ответ 15

Поскольку я начал делать несколько вещей в ядре linux, gotos не беспокоят меня так, как они когда-то делали. Сначала я был в ужасе, увидев, что они (парни ядра) добавили gotos в мой код. С тех пор я привык к использованию gotos, в некоторых ограниченных контекстах, и теперь изредка использую их сам. Как правило, это goto, который переходит к концу функции, чтобы сделать какую-то очистку и выручить, вместо того, чтобы дублировать эту же очистку и спасение в нескольких местах функции. И, как правило, это не что-то достаточно большое, чтобы передать другую функцию - например. освобождение некоторых локально (k) переменных malloc'ed является типичным случаем.

Я написал код, который использовал setjmp/longjmp только один раз. Это было в программе MIDI-секвенсора. Воспроизведение происходило в отдельном процессе из всех пользовательских взаимодействий, а процесс воспроизведения использовал разделяемую память с процессом пользовательского интерфейса, чтобы получить ограниченную информацию, необходимую для воспроизведения. Когда пользователь хотел остановить воспроизведение, процесс воспроизведения просто запустил longjmp "назад к началу", а не некоторое сложное разворачивание, где бы он ни выполнялся, когда пользователь хотел его остановить. Он отлично работал, был простым, и у меня никогда не было никаких проблем или ошибок, связанных с ним в этом случае.

setjmp/longjmp имеют свое место - но это место - это то, которое вы вряд ли посещаете, но раз в очень долгое время.

Изменить: я просто посмотрел на код. Это был фактически siglongjmp(), который я использовал, а не longjmp (не то, чтобы это было большим делом, но я забыл, что siglongjmp даже существовал.)

Ответ 16

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

Ответ 17

Если вы пишете виртуальную машину на C, получается, что с использованием (gcc) вычисленных gotos, таких как:

char run(char *pc) {
    void *opcodes[3] = {&&op_inc, &&op_lda_direct, &&op_hlt};
    #define NEXT_INSTR(stride) goto *(opcodes[*(pc += stride)])
    NEXT_INSTR(0);
    op_inc:
    ++acc;
    NEXT_INSTR(1);
    op_lda_direct:
    acc = ram[++pc];
    NEXT_INSTR(1);
    op_hlt:
    return acc;
}

работает намного быстрее, чем обычный переключатель внутри цикла.

Ответ 18

Поскольку goto может использоваться для запутывания метапрограммирования

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

Это низкий уровень в том смысле, что goto является примитивной операцией, которая реализует нечто более высокое, например while или foreach или что-то в этом роде.

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

Итак, есть прозаическая и злая сторона goto.

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

Злая сторона включает в себя рутину, не использующую goto для while, break или return, но используя ее для того, что называется логикой спагетти. В этом случае goto-happy разработчик строит фрагменты кода из лабиринта goto's, и единственный способ понять это - имитировать его мысленно в целом, ужасно утомительную задачу, когда есть много goto's. Я имею в виду, представьте себе проблему с оценкой кода, где else не является точно обратным к if, где вложенный if может разрешить в некоторых вещах, которые были отвергнуты внешним if и т.д. И т.д.

Наконец, чтобы действительно осветить тему, мы должны отметить, что по существу все ранние языки, кроме Algol, первоначально делали только одиночные утверждения, подчиненные их версиям if-then-else. Таким образом, единственный способ сделать условный блок - goto вокруг него с использованием инверсного условного. Безумный, я знаю, но я прочитал некоторые старые спецификации. Помните, что первые компьютеры были запрограммированы в двоичном коде машины, поэтому я полагаю, что любой вид HLL был спасателем; Я думаю, они не были слишком разборчивы в отношении того, какие функции HLL они получили.

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

Ответ 19

Отказ от использования оператора GOTO для программистов - это сказать плотнику, чтобы он не использовал молоток, поскольку он может повредить стену, когда он забивает гвоздь. Настоящий программист знает, как и когда использовать GOTO. Ive последовал за некоторыми из этих так называемых "Структурированных программ". Я вижу такой код Horrid, чтобы избежать использования GOTO, чтобы я мог снимать программиста. Хорошо, в защиту другой стороны, я видел и некоторые реальные коды спагетти, и тех программистов тоже нужно снимать.

Вот только один маленький пример кода, который я нашел.

  YORN = ''
  LOOP
  UNTIL YORN = 'Y' OR YORN = 'N' DO
     CRT 'Is this correct? (Y/N) : ':
     INPUT YORN
  REPEAT
  IF YORN = 'N' THEN
     CRT 'Aborted!'
     STOP
  END

----------------------- ИЛИ ----------------------

10:  CRT 'Is this Correct (Y)es/(N)o ':

     INPUT YORN

     IF YORN='N' THEN
        CRT 'Aborted!'
        STOP
     ENDIF
     IF YORN<>'Y' THEN GOTO 10

Ответ 20

"В этой ссылке http://kerneltrap.org/node/553/2131"

По иронии судьбы, устранение goto ввело ошибку: вызов spinlock был опущен.

Ответ 21

Оригинальную статью следует рассматривать как "безусловный GOTO считается вредным". Он, в частности, выступал за форму программирования, основанную на условных (if) и итеративных конструкциях (while), а не на тестах и ​​прыжках, общих для раннего кода. goto по-прежнему полезен в некоторых языках или обстоятельствах, где не существует соответствующей структуры управления.

Ответ 22

О единственном месте, где я согласен, можно использовать Goto, когда вам нужно иметь дело с ошибками, и каждая конкретная точка возникает ошибка, требующая специальной обработки.

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

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

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

-Adam

Ответ 23

Одно современное использование GOTO компилятором С# для создания состояний машин для счетчиков, определенных возвратом доходности.

GOTO - это то, что должно использоваться компиляторами, а не программистами.

Ответ 24

До тех пор, пока C и С++ (среди других преступников) не будут отмечены перерывы и будут продолжать, goto будет продолжать играть роль.

Ответ 25

Если бы сам GOTO был злым, компиляторы были бы злыми, потому что они генерировали JMP. Если прыгать в блок кода, особенно после указателя, по своей природе зла, инструкция RETurn будет злой. Скорее, зло может потенциально злоупотреблять.

Иногда мне приходилось писать приложения, которые должны были отслеживать количество объектов, где каждый объект должен был следовать за сложной последовательностью состояний в ответ на события, но все это было, безусловно, однопоточным. Типичная последовательность состояний, если она представлена ​​в псевдокоде, будет:

request something
wait for it to be done
while some condition
    request something
    wait for it
    if one response
        while another condition
            request something
            wait for it
            do something
        endwhile
        request one more thing
        wait for it
    else if some other response
        ... some other similar sequence ...
    ... etc, etc.
endwhile

Я уверен, что это не ново, но способ, которым я его обрабатывал в C (++), заключался в определении некоторых макросов:

#define WAIT(n) do{state=(n); enque(this); return; L##n:;}while(0)
#define DONE state = -1

#define DISPATCH0 if state < 0) return;
#define DISPATCH1 if(state==1) goto L1; DISPATCH0
#define DISPATCH2 if(state==2) goto L2; DISPATCH1
#define DISPATCH3 if(state==3) goto L3; DISPATCH2
#define DISPATCH4 if(state==4) goto L4; DISPATCH3
... as needed ...

Затем (при условии, что состояние изначально 0) машина с структурированным состоянием выше превращается в структурированный код:

{
    DISPATCH4; // or as high a number as needed
    request something;
    WAIT(1); // each WAIT has a different number
    while (some condition){
        request something;
        WAIT(2);
        if (one response){
            while (another condition){
                request something;
                WAIT(3);
                do something;
            }
            request one more thing;
            WAIT(4);
        }
        else if (some other response){
            ... some other similar sequence ...
        }
        ... etc, etc.
    }
    DONE;
}

С изменением этого может быть CALL и RETURN, поэтому некоторые государственные машины могут действовать как подпрограммы других состояний.

Это необычно? Да. Требуется ли некоторое обучение со стороны сопровождающего? Да. Означает ли это обучение? Я думаю так. Может ли это быть сделано без GOTO, которые прыгают в блоки? Нет.

Ответ 26

Я избегаю этого, так как коллега/менеджер, несомненно, сомневается в его использовании либо в обзоре кода, либо когда он наткнется на него. Хотя я думаю, что он использует (например, пример обработки ошибок) - вы столкнетесь с каким-то другим разработчиком, у которого будет какая-то проблема с ним.

Его не стоит.

Ответ 27

Я действительно нашел себя вынужденным использовать goto, потому что я буквально не мог придумать лучшего (более быстрого) способа написать этот код:

У меня был сложный объект, и мне нужно было выполнить некоторую операцию над ним. Если объект находился в одном состоянии, я мог бы выполнить быструю версию операции, иначе мне пришлось бы выполнять медленную версию операции. Дело в том, что в некоторых случаях, в середине медленной операции, можно было понять, что это можно было бы сделать с быстрой операцией.

SomeObject someObject;    

if (someObject.IsComplex())    // this test is trivial
{
    // begin slow calculations here
    if (result of calculations)
    {
        // just discovered that I could use the fast calculation !
        goto Fast_Calculations;
    }
    // do the rest of the slow calculations here
    return;
}

if (someObject.IsmediumComplex())    // this test is slightly less trivial
{
    Fast_Calculations:
    // Do fast calculations
    return;
}

// object is simple, no calculations needed.

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

Уго

Ответ 28

Практически во всех ситуациях, когда можно использовать goto, вы можете сделать то же самое с помощью других конструкций. Goto все равно используется компилятором.

Я лично никогда не использую его явно, никогда не нужно.

Ответ 29

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

Рассмотрим случай с множеством вложенных циклов, где использование "goto" вместо кучки разделов if(breakVariable), очевидно, более эффективно. Решение "Положите свои петли в функцию и используйте возврат", часто совершенно необоснованно. В вероятном случае, когда циклы используют локальные переменные, теперь вы должны передавать их через функциональные параметры, потенциально обрабатывая множество дополнительных головных болей, которые возникают из-за этого.

Теперь рассмотрим случай очистки, который я использовал сам довольно часто, и настолько распространен, что предположительно был ответственным за структуру try {} catch {}, недоступную на многих языках. Количество проверок и дополнительных переменных, которые требуются для достижения того же самого, намного хуже, чем одна или две инструкции для совершения прыжка, и снова дополнительное решение функции не является решением вообще. Вы не можете сказать мне, что это более управляемое или более читаемое.

Теперь кодовое пространство, использование стека и время выполнения могут не иметь большого значения во многих ситуациях для многих программистов, но когда вы находитесь во встроенной среде с объемом всего 2 КБ для работы, 50 байтов дополнительных инструкций, чтобы избежать один четко определенный "goto" просто смехотворный, и это не такая редкая ситуация, как полагают многие высокопоставленные программисты.

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

Ответ 30

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