Запретный плод GOTO сладок!

    Доброго времени суток!

    Какое Ваше отношение к оператору goto в языках С/С++? Скорее всего, когда Вы учились программировать, Вы его использовали. Потом Вы узнали, что это плохо, и Вы о нем позабыли. Хотя иногда при сложной обработке ошибок… нет-нет, там try … throw … catch. Или же для выхода из вложенных циклов … не-ет, там флаги и куча сложностей. Или когда вложенные switch … нет-нет-нет, там те же флаги.
    И все-таки, иногда в ночной тиши Вы допускали в свое подсознание грешную мысль – «а почему бы не использовать вот тут goto? И программа вроде как стройней будет, и оптимально выходит. Да-а, было бы хорошо… Но нет – нельзя, забыли!».
    А почему так оно?
    Под катом – небольшое расследование и мое, основанное на многолетней практике и разных платформах, отношение к этому вопросу
    UPD: тут статья рассматривает С и С++, программирование для PC и слегка для микроконтроллеров. Конкретно о микроконтроллерах есть другая статья.

    Просьба к ярым противникам goto – не свергайте меня в геенну огненную минусовой кармы только из-за того, что я поднял эту тему и являюсь частичным сторонником goto!

    Небольшой исторический экскурс


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

    А все начиналось с комбинационных схем



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

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

    Для решения этой сложнейшей задачи строился последовательный алгоритм для выполнения арифметических операций (в случае заданной точности вычислений в таком алгоритме каждое арифметическое действие можно выполнять за один такт).

    Имея алгоритм, несложно построить комбинационную схему – схему, которая мгновенно (с точностью до срабатывания логических устройств и времени распространения сигналов) на выходе давала ответ.
    Вопрос – тут нужны какие-нибудь переходы? Нет, их тут просто-напросто нет. Есть последовательное течение действий. Все эти действия можно реализовать в конечном счете за один такт (не спорю, это будет очень и очень громоздко, но задавшись разрядностью всех данных, такую схему Вам построит любой студент – и тем более синтезатор для VHDL или Verilog).

    Но потом вмешались схемы с памятью



    А потом чья-то умная голова додумалась до схемы с обратной связью – например, RS-триггер. И тогда появилось состояние схемы. А состояние – это ни что иное, как текущее значение всех элементов с памятью.

    Появление таких элементов памяти позволило сделать революционный скачок вперед от жестко заданных устройств к микропрограммным автоматам. Упрощенно говоря, в микропрограммных автоматах есть память команд. Есть отдельное устройство, которое реализует текущую микропрограмму (сложение, вычитание или еще чего). А вот выбором «текущей» микропрограммы занимается отдельное устройство – пусть это будет «устройство выборки».

    Вопрос – тут есть какие-нибудь переходы? Однозначно да! Более того, появляются переходы безусловные (адрес следующей команды не зависит от текущего состояния данных) и условные (адрес следующей команды зависит от состояния данных).

    Можно ли без них обойтись? Да никак! Если не использовать переходы, то мы вернемся к комбинационной схеме без памяти.

    В итоге мы пришли к ассемблеру


    Апофеозом таких вычислительных устройств стали микро-, просто- и супер-компьютеры. Все они в основе имеют язык кодов, достаточно легко преобразуемый в Ассемблер с приблизительно совпадающим набором команд. Возьмем самый массовый персональный компьютер с Ассемблером от i386 процессора – благо, Windows XP написан для него. Как у него построена работа?

    В данном процессоре память данных и команд общая, идентифицируется адресом. Команды не имеют фиксированную длину. Если не используется команда перехода, то следующей командой выполняется команда, расположенная сразу за текущей.

    Есть также набор goto-команд. Они бывают безусловные (просто переход на следующий адрес – jmp, переход в подпрограмму – call, выход из нее – ret, вызов прерывания – int) и условные (в зависимости от состояния флагов – jnz, jne, jz, …). Есть также команда для создания циклов – loop. Она 1) делает -1 регистру CX/ECX и 2) переходит на указанный адрес, если этот регистр ненулевой.
    В плане операций переходов другие массовые ассемблеры (те же микроконтроллеры) принципиально не отличаются – разве что нет возможности программно вызвать прерывание и не везде есть loop.
    Со всей ответственностью заявляю – без операций перехода в ассемблере обойтись невозможно! Любая программа на ассемблере просто таки пестрит ими! Впрочем, тут со мной никто спорить, я думаю, не будет.

    Итог


    Какой итог можно подвести? На уровне микропроцессора операции перехода используются очень активно. Реальную программу, их не использующую, написать почти невозможно (может быть, ее можно сделать, но это будет супер-мега-извращение и точно уж не реальная программа!). С этим тоже спорить никто не будет.

    Но почему же тогда в языках более высокого уровня – сконцентрируемся на С/С++ — оператор goto вдруг впал в немилость?..

    Немного об алгоритмах




    А теперь посмотрим на хитровывернутый алгоритм. Представление не имею что это за бред – но его надо реализовать.

    UPD: здесь A, B, C, D, E — это некоторые операции, а не вызов функции! Вполне возможно, что они используют массу локальных переменных. И вполне возможно, что они меняют их состояние. Т. е. в данном случае речь не идет о вызове функций — некоторые действия, не будем детализировать.

    Вот как это выглядит в С с goto:

    if (a)
    {
    	A;
    	goto L3;
    }
    L1:
    if (b)
    {
    L2:
    	B;
    L3:
    	C;
    	goto L1;
    }
    else if (!c)
    {
    	D;
    	goto L2;
    }
    E;
     
    


    Очень лаконично и читабельно. Но — нельзя! Попробуем без goto:

    char bf1, bf2, bf3;
    
    if (a)
    {
    	A;
    	bf1 = 1;
    }
    else
    	bf1 = 0;
    
    bf2 = 0;
    do
    {
    	do
    	{
    		if (bf3 || b)
    			bf3 = 1;
    		else
    			bf3 = 0;
    		if (bf3 || bf2)
    			B;
    		if (bf3 || bf1 || bf2)
    		{
    			C;
    			bf1 = 0;
    			bf2 = 1;
    		}
    		if (!bf3)
    		{
    			if (!c)
    			{
    				D;
    				bf3 = 1;
    			}
    			else
    			{
    				bf3 = 0;
    				bf2 = 0;
    			}
    		}
    	}
    	while (bf3);
    }
    while (bf2);
    
    E; 
    


    Вы что-нибудь поняли из логики работы второго листинга?..
    Сравним оба листинга:

    • На первый листинг я потратил раз в 5 меньше времени, чем на второй.
    • Листинг с goto короче как минимум в 2 раза.
    • Листинг с goto поймет любой человек с самой минимальной подготовкой в С. Второй же я постарался сделать максимально доступным и очевидным – и все равно, в него надо долго вникать.
    • Сколько времени уйдет на отладку первого варианта и сколько на отладку второго?
    • И вообще, если считать нарисованный алгоритм постановкой задачи, то первый листинг правильный на 100%. Про второй я до сих пор не очень уверен… хотя бы в очередности проверки условий и флагов.
    • Сравните получившийся ассемблерный код первого и второго листинга.


    Но зато во втором листинге нет goto!

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

    goto в реальных программах



    Я за свой более чем 20-летний стаж прошел несколько аппаратных платформ и с десяток языков программирования, участвовал в написании крупного программного продукта ActiveHDL, делал коммерческую базу данных и много небольших программ для отладки оборудования, используемого в Олимпийских играх, а также делал устройства для этой самой Олимпиады (уже несколько Олимпиад, если быть точным). Короче, что-то я в программировании шарю. А, да, забыл – я закончил с почетным дипломом ХНУРЭ — то бишь, в теории я тоже секу.

    Поэтому мои последующие размышления и ситуации… скажем так, я имею моральное право на них.

    Неявное использование goto


    В языке С есть много операторов, которые на самом деле являются банальным goto – условным или безусловным. Это все виды циклов for (…), while (…) {…}, do {…} while (…). Это анализ числовых переменных switch (…) {case … case …}. Это те же операторы прерывания/перехода в циклах break и continue. В конце концов, Это вызовы функций funct() и выход из них return.

    С++ добавляет массу невидимых переходов перегрузками, конструкторами и деструкторами. Из явных переходов – try {… throw …} catch (…) {…}.

    Эти goto считаются «легальными» — чем же нелегален сам goto?

    В чем обвиняют goto


    Обвиняют его в том, что код становится нечитабельным, плохо оптимизируемым и могут появиться ошибки. Это про практические минусы. А теоретические – это просто плохо и неграмотно, и все тут!

    Насчет нечитабельности кода и плохой оптимизируемости – еще раз взгляните на листинги выше.
    Насчет вероятности появления ошибок – согласен, такой код воспринимается несколько сложнее из-за того, что мы привыкли читать листинг сверху вниз. Но и все! А что, другие средства С++ безопасные и не могут создать ошибок в коде? Приведу краткий список самых опасных вещей С++ («опасные» в том смысле, что с их помощью можно создать массу трудноуловимых ошибок): преобразования типов, перегрузка операторов, указатели и динамическое распределение памяти, наследование классов, шаблоны… Кажется, я перечислил почти все достоинства С++… А, ну да, полиморфизм не назвал – он у меня проходит под «перегрузкой операторов».

    Вам не кажется, что нож – это очччень опасная вещь? Но почему-то на кухне мы им пользуемся. А 220 вольт – ужас как опасно! Но если пользоваться с умом – жить можно.

    Тоже самое и goto. Пользоваться им надо с умом – и тогда код будет работать корректно.

    А про теоретические доводы – это, уж простите меня, спор о вкусах. Вы пользуетесь Венгерской нотацией? Я – нет, терпеть ее не могу! Но я ж не говорю, что она плохая из-за этого! Лично я считаю, что переменная должна нести смысловую нагрузку – для чего она создана. Но я не буду запрещать пользоваться этим способом именования другим людям!

    Или же есть эстеты, которые считают, что писать a = ++i неграмотно, надо писать i = i + 1; a = i. И что теперь, запретить и это тоже?

    Впрочем, есть в C++ ньюанс, где goto приводит к проблемам:

    goto Label;
    
    for (;;)
    {
    	int p = 0;
    Label:
    	p += 10;
    }
    


    Чему будет равно p? А компилятор его знает! Впрочем, хороший компилятор такого не допустит – или допустит в том случае, если это p нигде не используется.

    В то же время выход из цикла вызывает необходимые деструкторы – проверено в Visual Studio 2008.
    Что на это скажешь? А то, что не-использование goto не застрахует Вас от неправильно написанной программы. Так же и применение его не гарантирует, что программа будет сыпаться. Нужно писать программы с умом и не делать таких элементарных глюков.

    Обработка ошибок


    В С++ по сравнению с С появилась замечательная возможность try … throw … catch. Она позволяет эффективно обрабатывать ошибки и прочие сложные ветвления. В С++ — да, но не в С. В С приходится в таком случае использовать goto. Разумеется, можно использовать всяческие флаги и прочее. Но этот вопрос мы уже обсудили – код раздувается, появляются источники новых ошибок, листинг становится нечитабельным.

    Это как раз тот самый случай при программировании микроконтроллеров, где я активно использую goto. Это мне позволило не попадать в «зависания» в случае проблем с внешними устройствами, UART, USB и т. п.

    Выход из вложенного цикла наружу


    Посмотрите на программу ниже:

    char a, b, c;
    
    for (a = 0; a < 10; ++a)
    {
    	for (b = 0; b < a; ++b)
    	{
    		if (!c)
    			goto Leave;
    	}
    	for (b = 10; b < 15; ++b)
    	{
    		d ();
    	}
    }
    
    Leave:
    e ();
    


    Что происходит – понятно? Есть вложенный цикл. Если наступило какое-то условие – покидаем все последующие обработки.

    Данный код с флагами выглядит иначе:

    char a, b, c, f1;
    
    f1 = 1;
    for (a = 0; a < 10 && f1; ++a)
    {
    	for (b = 0; b < a && f1; ++b)
    	{
    		if (!c)
    			f1 = 0;
    	}
    	if (f1)
    	{
    		for (b = 10; b < 15; ++b)
    		{
    			d ();
    		}
    	}
    }
    
    e ();
    


    Что произошло в данном случае? На каждой итерации мы теперь проверяем флаг. Не забываем его проверять и дальше. Это мелочи, если итераций немного и речь идет о «безразмерной» памяти у PC. А когда программа написана для микроконтроллера – это все уже становится существенно.

    Кстати, в связи с этим в некоторых языках (если не ошибаюсь, в Java) есть возможность выйти из цикла по метке вида break Leave. Тот же goto, между прочим!

    Точно такой же пример я могу привести и с обработкой в switch (…) { case …}. С этим я сталкиваюсь часто при обработке входящих пакетов неодинаковой структуры.

    UPD: как мне справедливо подсказали, в данном случае это проблема для С, а не С++. В С++ можно «выскользнуть» наружу с помощью throw… catch…. Но мы помним, что throw… catch… — тот же самый goto!

    Автоматическое создание кода


    Знакомы ли Вы с автоматным программированием? Или любым другим автоматизированным созданием кода? Скажем, создатели лексических обработчиков (без использования громоздкого boost::spirit). Все эти программы создают код, который можно использовать как «черный ящик» — Вам не важно, что там внутри; Вам важно, что он делает. А внутри там goto используется очень и очень часто…

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

    Выход в одном месте


    На С иногда приходится писать что-то вроде:

    int f (…)
    {
    	…
    	if (a)
    	{
    		c = 15;
    		return 10;
    	}
    	…
    	if (b)
    	{
    		c = 15;
    		return 10;
    	}
    	…
    	с = 10;
    	return 5;
    }
    


    Этот код гораздо аккуратней будет выглядеть так:

    int f (…)
    {
    	…
    	if (a)
    		goto Exit;
    	…
    	if (b)
    		goto Exit;
    
    	…
    	с = 10;
    	return 5;
    Exit:
    	c = 15;
    	return 10;
    }
    


    Идея понятна? Иногда надо при выходе что-то сделать. Иногда много чего надо сделать. И тогда тут здорово помогает goto. Такие примеры у меня тоже имеются.
    Вроде бы все перечислил, теперь можно подвести…

    Итог



    Это моя точка зрения! И она справедлива для меня. Может – и для Вас, но я не буду Вас заставлять ей следовать!

    Так вот, для меня очевидно, что goto помогает оптимальней и качественней решить некоторые проблемы.
    А бывает и наоборот – goto может породить массу проблем.

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

    Плюсы использования goto:
    • самый оптимальный (с т. зр. листинга и результирующего кода) выход из нескольких вложенных циклов и switch… case
    • Си: наиболее экономичный (по листингу и результирующему коду) способ обработки ошибок
    • в отдельно взятых случаях самое оптимальное построение алгоритма
    • экономит память и такты при аккуратном использовании, что иной раз бывает первостепенно важным

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


    Кто еще подскажет плюсы/минусы? Впишу, если они будут оправданы.
    Share post

    Comments 272

      –12
      goto не нужен. goto плох тем, что программу сложно понимать и отлаживать.
      switch — тоже несколько спорная команда, зачастую от неё можно (и нужно) избавляться при помощи, например, полиморфизма.

      Все ваши примеры опровергать не буду, достаточно последнего: оттуда можно просто убрать goto, разве нет?

      int f (…)
      {

      if (a)

      if (b)


      c = 15;
      return 10;
      }


      Ну и пост будет неполон без этого:
      image
        0
        Я написал простейшую программу. Но хорошо, можно несколько усложнить пример. Посмотрите — я исправил
          0
          Ок, я понял, что рассмотрение этих надуманных функций — бессмысленно.
          Давайте реальный пример, из реального приложения на языке высокого уровня рассмотрим. Без троеточий.
            +6
            goto подобен ножу — малых детей лучше напугать, чтобы не пользовались, а не то натворят многочасовой отладки бед себе и другим.
            Если же ты знаешь как и когда им можно пользоваться, то почему бы и нет, главное чтобы малые дети этого не увидели в вашем коде. Не то, см. выше! :)
              +1
              Ну-у, это надо покопаться — если для С++. А для С — примеров куча, но для микроконтроллеров
                +2
                В том-то и дело, хотелось бы увидеть пример для высокоуровневых языков C++, или C#, или Java.
                У меня, конечно, не 20 лет опыта, но лет 6 уже получаю деньги за программирование (C#), и до сих пор ни разу не возникало нужды в goto.

                А про системное программирование и микроконтроллеры спорить не буду, видимо, был не прав.
                  0
                  Вспомнил! В С++ была достаточно сложная программа, где на основе данных из XML строилась структура тестов для устройства. Причем для конкретных шагов тестов из того же XML брались параметры теста — кол-во шагов, настройка конкретных величин и т. п.
                  И там не раз встречались ситуации необходимости выхода из глубин нескольких вложенных циклов с обходом последующих проверок.

                  В другой раз был случай, когда приходилось переходить назад — и там введение do… while () выглядело весьма криво. Тогда-то я впервые и задумался о том, что иногда goto лучше других способов.
                    +2
                    Если вы 6 лет зарабатываете программированием, наверняка сталкивались с вложенными циклами. Это именно тот момент, который заставляет меня каждый раз вспоминать про GOTO, но… нельзя. Коллеги не оценят
                      +4
                      Кстати, в Perl можно ставить метку перед циклом и потом пользоваться last/next (break/continue) с меткой. В C++ иногда действительно не хватает.
                        0
                        толково придумано
                          +2
                          Аналогично и в Java, причём метка может быть не только у цикла, но у любого блока кода.
                          +3
                          Конечно, сталкивался. В случае, когда нужно «выпрыгнуть» из нескольких вложенных циклов, я обычно выделяю метод и использую return.

                          В общем, по-прежнему здесь нет ни одного примера «жизненного» кода, где goto облегчал бы жизнь.
                            –1
                            не вижу никаких преимуществ у выделении подцикла в процедуру перед goto, кроме массы лишнего кода. А если вложенных циклов не два и не три?
                  +9
                  «goto не нужен. goto плох тем, что программу сложно понимать и отлаживать.»
                  А Вы читали мой топик? Первый же пример Вас опровергает
                    +3
                    > более чем 20-летний стаж

                    Вы программируете с 10 лет? Жесть… :)
                      0
                      С 7-ми — дальше в комментариях посмотрите
                        0
                        Ага, Оk, увидел :)
                        Ну, круто!
                      +1
                      Сколько времени уйдет на отладку первого варианта и сколько на отладку второго?
                      Конечно, без goto отлаживать легче. Я в каждый момент времени знаю, в каком состоянии, в какой части цикла я нахожусь, и что меня не перекинет к чертовой матери, пока не перестанет действовать то или иное условие. В случае с таким обилием goto я такой логикой руководствоваться не могу.
                      А когда программа написана для микроконтроллера – это все уже становится существенно.
                      Не надо все в кучу. Микроконтроллер и десктоп — очень разные вещи с точки зрения политики программирования.

                      Я не противник goto. Но на мой взгляд, вы сильно передернули (гусары, молчать!).
                        +4
                        Конечно, читал. Первый пример некорректен, ниже есть объяснение:
                        habrahabr.ru/blogs/cpp/114211/#comment_3682679
                        +6
                        Нельзя быть столь категоричным. В простых случаях, когда количество элементов в enum'е мало того, что не меняется со временем, но еще и в RFC прописано, то switch просто то, что доктор прописал: читабельно и понятно.
                        Насчет точек выхода из функции: ну так даже если 100500 return'ов написать, то точка выхода всё равно одна останется. В общем это дело на любителя.
                        Разрабы ядра linux юзают goto и их волосы мягкие и шелковистые
                          0
                          Я тоже не считаю goto дурным тоном, но по возможности стараюсь избегать его… ибо при отладке бывает сложно отследить что-куда прыгает :)
                            0
                            > Насчет точек выхода из функции: ну так даже если 100500 return'ов написать, то точка выхода всё равно одна
                            В машинном коде, конечно, одна, но в тексте C/C++ — нет. А программисту-то читать последний — машинный его на так интересует.
                              +1
                              Не вижу особой разницы в читабельности между return a и goto Exit;
                                0
                                Я тоже, поэтому return в теле функции использую очень редко, только если без него очень уж громоздкие конструкции получаются.
                                  +1
                                  Разница хотя бы в том, что про return абсолютно точно известно, что произойдёт, а про goto Exit нужно ещё смотреть, куда оно на самом деле прыгает и что делает после перехода.
                              0
                              Есть алгоритмы, которые без goto, во-первых, не понятны, а во-вторых не эффективны. Например, разбор последовательных протоколов.
                                0
                                Можно код из реальной жизни в студию?
                                  0
                                  Я когда-то писал достаточно сложный пасрер, еще не зная про boost::spirit — и там активно использовался goto. Вначале я выкручивался всяческими while… break…, но потом увидел, что код угрожающе растет и становится нечитабельным — перешел к goto и все стало значительно лучше
                                +3
                                В системном программировании без goto очень печально.
                                  +1
                                  GOTOзилла?
                                  +15
                                  Все хорошо в меру.
                                  Когда знаешь где и как можно использовать goto без вреда — нет проблем.
                                  А когда разбираешь программу где КАЖДЫЙ условный переход сделан с GOTO (Язык — С)?
                                  if() goto P1;
                                  else goto p2;


                                  Спрашиваешь «Зачем?». А в ответ — я так привык… Когда сам изучал бейсик.
                                  Вот из-за этого лично я против данного оператора.
                                  Да, он иногда чрезвычайно удобен. Но это именно ИНОГДА.
                                    +2
                                    Мне кажется, нужно быть против таких людей типа «Я привык», «Мне так сказали», а не против инструмента языка, коим также является и goto
                                      +1
                                      Согласен.
                                      Но со свободой в действиях, которую дает goto не каждый может управиться.
                                      Именно поэтому goto надо применять именно тогда, когда без него не обойтись.
                                      В остальных же случаях знание об этом операторе скорее всего пойдет во вред.
                                      Именно поэтому и есть правило «не использовать goto». А как известно, из каждого правила есть исключения. И только опыт позволяет понять когда это исключение наступило.

                                      Я могу вспомнить всего несколько случаев, когда мне пришлось воспользоваться goto. И всего 1 раз это было оправданное использование (алгоритм был завязан на этот оператор).
                                    0
                                    А на мой взгляд goto это — зло. Его использование приводит к появлению ошибок. Сомневаюсь, что компилятор сможет оптимизировать код, напичканный goto.

                                    Согласен, возможны редкие ситуации, когда он увеличивает читаемость. Единственный общий случай, когда я признаю оправданность его использования — выход из вложенного цикла. Собственно для этого в Java и модернизировали оператор break.
                                      +2
                                      Скорее они урезали и переименовали оператор goto ;)
                                        0
                                        if с точки зрения ассемблера это частный случай goto — и он прекрасно транслируется в jne, jz или jmp в случае безусловного перехода. Уверен компилятор прекрасно знает как с этим справляться, а оптимизировать ассемблерные инструкции это вроде бы перебор.
                                          +1
                                          Не столь уменьшает читаемость goto, как быдлокод. Но использовать безусловный переход имеет смысл только там, где без него не обойтись, и то с ограничениями (вменяемые имена меток и их расположения).
                                          +11
                                          AFAIK, пространное эссе на тему «goto — зло» появилось в ту эпоху, когда по меткам можно было переходить не то что в циклы — в другие подпрограммы! Вот тогда — да, goto вносило огромную сложность. Сейчас же — если писать по человечески (небольшие функции, внятная нотация), то goto не внесет дополнительной сложности в понимание программы.

                                          Вот здесь есть хороший пример грамотного применения goto: sim0nsays.livejournal.com/31460.html
                                            +3
                                            Эта статья справедлива больше к С а не к С++. Ели мы говорим о С++ — то есть об ООП, то тут более актуальна как по мне вот эта статья — habrahabr.ru/blogs/cpp/112123/.
                                              0
                                              Собственно говоря, эту статью хорошо бы разбить на две — одна для С++, вторая для С. Но они будут на 80% перекрываться, я это копипаст…
                                              +5
                                              «нельзя Goto», «ООП ради ООП» все это как по мне из одной оперы. Когда задачу может решить любой надо придумать что-то новое, более сложное, чтоб прграммисту платили больше, поскольку реально сложных проэктов единицы, а программистов способных решать те же задачи но «на разных уровнях» миллион.
                                                +17
                                                Проблема надумана. Я пишу программы с 1987 и как то обходился.

                                                Меня вообще как то смущают темы «нужен ли goto» и «как написать пузырьковую сортировку» в 2011, на хабре, от людей с 20 летним стажем.
                                                  +2
                                                  Проблема как раз в том, что из использования goto создают проблему!
                                                  А тема — «размышления на тему». Когда я привел небольшой код с goto, меня наругали и сказали, что так делать низзя! Вот я и написал свои размышления на тему
                                                    0
                                                    Кстати ваш пример нормальный, когда он маленький по размеру. Но вот если между оператором goto и точкой куда идет переход будет увеличиваться количество строк, скажем так полгодика будет расти, то этот гоуту станет Очень не очевидным. В принципе та можно использовать, используя те же методы выноса становящегося сложного кода в функции, но я искренне не понимаю зачем :). У меня действительно не было случая, когда я хотел бы его использовать.
                                                    +1
                                                    Я всё детство провёл с Basic и Assembler на ZX-Spectrum. Там вообще никак без GO TO. Когда попробовал писать небольшие программы для 386 на qbasic тоже GOTO применял. Вот там было страшно самому на код смотреть через месяц. Всё-таки GOTO (Jump и т.п.) для процессора близки. Чем ниже язык программирования тем больший выйгрыш можно получить при оптимальном использовании переходов. Главное не перебарщивать, как это делал я в своё время на qbasic.
                                                      0
                                                      Да, помнится, на Basic-е я тоже полюблЯл goto… За что мне понравился потом С — за свою элегантность и возможность по-разному написать одно и то же — в том числе обходиться без goto :-)
                                                        0
                                                        На Спектруме увы C не было. А когда появился PC, то интернета не было. И книг тоже. Так что завис очень на долго в «вакуумном» информационном пространстве.
                                                          0
                                                          Был :)
                                                    +2
                                                    Еще не дочитали до обработки исключений? :)
                                                      +2
                                                      В Си есть исключения?
                                                        0
                                                        Давайте тогда на ассемблер вернемся :) во-первых, блог посвящен С++, во-вторых, в чем С лучше С++? Или до С++ тоже «не дочитали еще»?
                                                          +2
                                                          А на чем еще драйвера писать? Не на С++ же! goto как раз активно и нужен в драйверописательстве.
                                                            0
                                                            Соглашусь.
                                                            Для языка чуть выше ассемблера это вещь нужная и правильная.
                                                            Но обобщать-то зачем?
                                                              0
                                                              Где я обобщал?
                                                                +1
                                                                Не вы.
                                                                Топикстартер.
                                                                  0
                                                                  успокойтесь, ребята, есть в С исключения. Называется longjmp :)

                                                                  и без шуток, его стоит научиться готовить.
                                                        0
                                                        А хорошо ли вообще использовать исключения где-либо, кроме обработки нештатных ситуаций? Сейчас при отладке программы я могу запустить дебагер «до первого Exception» (системного или пользовательского), и там разобраться в том, что случилось. Если бы исключения вызывались где-нибудь в обработке штатной ситуации, то отладить программу не удалось бы никогда. Лучше уж goto.
                                                        Вообще я goto использую только для выхода из вложенных конструкций и вместо continue, когда нельзя выполнять проверку и последействие цикла. Например:

                                                        [code]
                                                        for(list a=A;a!=null;a=a->next){
                                                        _1:

                                                        if(....){
                                                        while(!p(a)) a=a->next;
                                                        if(a!=null) goto _1;
                                                        }

                                                        }
                                                        [/code]
                                                        А в большинстве случаев хватает break и return. Особенно радует цикл for(;;), который не выполняется ни одного раза — первое же выполнение всегда утыкается в break. Лучше это, чем goto или нет — не знаю.

                                                        А вот в конструкции
                                                        [code]
                                                        if(a){
                                                        b;
                                                        if© d;
                                                        }else d;
                                                        [/code]
                                                        где d — достаточно большой код, я goto не напишу. Лучше уж код скопировать. Потому что goto вглубь фигурных скобок — категорически низзя :)
                                                        +5
                                                        Кстати «более чем 20-летний стаж». Вы с 10 лет пишете?
                                                          0
                                                          С 7-ми, если быть точным :-). Еще до школы папа, который был преподаватель по информатике в ВУЗе, принес домой БКшку, а на его кафедре я с ДВКшками работал. Ну и с тех пор пошло-поехало. Через несколько лет я на ZX Spectrum драйвер на ассемблере.
                                                          Но вот когда я заикнулся на собеседовании о том же 20-летнем стаже, наступила гробовая тишина. Потом уточнили — «сколько лет вам платят за программирование?». Пришлось думать и уточнять %-)
                                                            +2
                                                            >Через несколько лет я на ZX Spectrum драйвер на ассемблере.
                                                            Да там собственно и драйверов то как таковых не было. Обычная работа с портами ввода/вывода. Не до драйверов было. Главное чтобы хоть как-то работало и в 48 килобайт умещалось :)
                                                              0
                                                              В каком-то смысле да. Фактически, это была программа для вывода текста на старый добрый принтер СМ… э-э… 6337, если мне не изменяет память. Драйвер был написан на ассемблере, а использовал я его из бэйсика
                                                                +2
                                                                Ну да. Это была некая прослойка. Она по просту была очень компактной и намного более быстродействующей.
                                                              +4
                                                              Вряд ли это можно отнести к стажу. Я, например, рисую лет с 2-3, но не буду писать, что мой стаж как художника 20 лет. :) И компьютер у меня появился лет в 5, как и у вас. Папа базы данных в универе читал. Поэтому вам задали правильный вопрос — сколько лет вы занимаетесь программированием профессионально, т.е. получаете за это деньги.
                                                                –3
                                                                Как бы там ни было, эффект я на девушку произвел сильный, а на ту работу я не стремился — так, решил проверить свой уровень :-).
                                                                К стажу я бы это отнес, потому что столь ранний старт и нехилое увлечение процессом дали мне большущий опыт решения всяких разных ситуаций
                                                                +4
                                                                Мне вот 21 лет но я блия уже 22 года программирую.
                                                                Я уже в животе матери началЪ. Причем сразу с генетических алгоритмов блият.

                                                                И я, о предвидец, говорю, что ваше goto нахуй не нужно на уровень >= C
                                                                  –2
                                                                  Вот уж не думал, что кого-то настолько задену упоминанием 7ми лет…
                                                                  Интересно бы узнать у уважаемого borius что именно он знает о генетических алгоритмах кроме названия. И сравнивал ли он их с методом сетей Петри или нечеткой логики.
                                                                    0
                                                                    О боже, а вы что, еще что-то кроме названии знаете?

                                                                    Я то не такой одаренный за 22 тяжелых года программирования я только имена смог постичь.

                                                                    Вы мой герой. Скажите можно ли у вас как нить отсосать?

                                                                    (П.с. а так метод сетей петри — конструкция показывающая что вы не знаете что это такое, хоть бы вики почитали и не позорились… хотя на хабре пох тут главное побольше умных слов)
                                                                      0
                                                                      Что я кроме названий знаю? Писал диссертацию с этими самыми сетями Петри — точнее говоря, разработал аналогичный аппарат, но на конечных автоматах.
                                                                      Нечеткая логика тоже неплохо позволяет решать задачи оптимизации (это то, для чего генетические алгоритмы используются)
                                                                        0
                                                                        Без издевки. Можно где-нибудь посмотреть Вашу диссертацию? Интересуюсь этим вопросом.
                                                                        > Нечеткая логика тоже неплохо позволяет решать задачи оптимизации
                                                                        Какие именно?
                                                                  –1
                                                                  знаете, а у меня точно так же, только что я на 5 лет моложе :)
                                                                +6
                                                                Сonsidering goto harmfull is considered harmfull.

                                                                Goto нужен при обработке ошибок и выходе из вложенных циклах (хотя иногда лучше просто заранее подумать и минимализировать кол-во таких циклов). Про «выход в одном месте», если это не эмуляция try-catch, я не согласен: обычно можно всё общее свернуть в вызов функции-хелпера.

                                                                Автор молодец — разжигает холивар, ожидаю в топике появления многих точек зрения :-)
                                                                  0
                                                                  А ведь действительно, конкретно в С++ из вложенных массивов можно «выскользнуть» по throw… catch… Как-то не подумал. Допишу в тексте
                                                                    0
                                                                    Если throw-catch — это тот-же самый goto (как написано в UPD), то тем-же самым goto является и любой цикл, и любое условие — ведь на уровне ассемблера кроме goto (jmp, j*) нет ничего, позволяющего делать ветвление. Так что такое замечание, как по мне, бессмысленно.
                                                                      –2
                                                                      Может, и бессмысленно, но напоминает нам, грешным, что goto есть везде, просто он политкорректно называется иначе
                                                                      • UFO just landed and posted this here
                                                                      +1
                                                                      [i]В С++ можно «выскользнуть» наружу с помощью throw… catch…[/i]
                                                                      Индусский код детектед. Вы в дизасме посмотрите для начала что получается =)

                                                                        0
                                                                        Ага! В том-то и оно, что самый чистый код дает именно goto, а все остальное — на совести компилятора! Кстати, может, стоит добавить раздел с дизассемблированием разных методов и их сравнением
                                                                        +1
                                                                        Для спасения из двух циклов меня иногда такой трюк выручает:

                                                                        for(i=0;i<10;i++)
                                                                        {
                                                                          for(j=0;j<20;j++)
                                                                          {
                                                                            if(f(i, j))
                                                                              break;
                                                                          }
                                                                        
                                                                          if(j<20)
                                                                            break;
                                                                        }
                                                                        

                                                                        Минусы — без лишних тормозов работает только для простых условий и требует чтобы 'j' была видима за пределами внутреннего цикла, т.е. for(int j=0;j<20;j++) не написать.

                                                                        Дальше по теме — больше всего бесит switch-case, т.к. в нём не сделать break/continue для цикла, содержащего этот switch/case :) Приходится заменять на if() else if() else if() только ради того чтобы break/continue относились не к свитчу, а к циклу.
                                                                          0
                                                                          Все проще. Один флаг который может выкинуть туда, куда нужно. При этом флаг несет через название понятный смысл его существования.
                                                                            0
                                                                            Флаги еще хуже чем goto. Из религиозных соображений крайне не приемлю вынесение codeflow в данные.
                                                                              0
                                                                              Чем флаги не угодили?
                                                                                0
                                                                                Тем что это костыли.
                                                                                  0
                                                                                  А так же тем, что съедают регистр/стек, замедляя выполнение кода на ровном месте. Я очень не уверен, что mainstream компиляторы смогут превратить код с флагами в goto-alike конструкцию вообще без переменной. В крайнем случае можно с самим собой договориться и использовать goto только в качестве break(n).
                                                                      • UFO just landed and posted this here
                                                                          0
                                                                          А зачем внешняя проверка?
                                                                            0
                                                                            Простите, понял.
                                                                            0
                                                                            Видел такое извращение:
                                                                            if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) ||
                                                                                (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) ||
                                                                                (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) 

                                                                            PS Не мое, это из исходников memcached.
                                                                              +2
                                                                              И в чем тут, позвольте спросить, извращение? я подобным образом у себя в проекте на С реализовал, правда я обернул в макрос, чтобы длину строки не считать. Единственное — плохо читается, но если разбивать на переменные, то теряем ленивую оптимизацию.
                                                                                0
                                                                                Самый, наверное, эффективный способ реализации синтаксических анализаторов
                                                                                  0
                                                                                  А к чему там strncmp()? В сравнении участвует константная Null-terminated строка.
                                                                                  Можно было обычным srtcmp() обойтись…
                                                                                    0
                                                                                    command имеет вид «add 1 2 ...». Поэтому сравниваются только первые 4 символа.
                                                                                      0
                                                                                      Я понимаю, как раз strlen(«add „) == 4, поэтому-то и можно обойтись strcmp() — после четырех символов цикл сам собой остановится.
                                                                                        0
                                                                                          +1
                                                                                          Да, туплю…

                                                                                          Конечно, strcmp() — это ж сравнение строк. Очевидно, если у строк разная длина — они уже не тождественны.

                                                                                          Вы правы! :)
                                                                                  0
                                                                                  Физбаз? :)
                                                                                  +1
                                                                                  Для меня самое зло goto в том, что с его помощью легко и непринужднно создаются циклы с несколькими входами, которые оптимизировать компилятору сущий ад. Это я со своей компиляторной колокольни :)
                                                                                    0
                                                                                    break туда же летит тогда и return в цикле тоже. Увы, но это тот же goto
                                                                                      0
                                                                                      С несколькими входами, не выходами. Выходы не мешают. С break и return полный порядок.
                                                                                        +3
                                                                                        Циклы с несколькими входами это по-моему форменное извращение и я бы на месте компилятора ругался бы.
                                                                                          +1
                                                                                          В спеке CPU2006 такой есть в одном из горячих циков, кстати. Я бы вообще за такое убивал.
                                                                                    0
                                                                                    Для меня goto появился в 8м классе вместе с «Sinclair ZX Spectrum», доставшийся со склада школьного в качестве игрушки.
                                                                                    Уже тогда я понимал, что он (goto) иногда чрезвычайно удобен.
                                                                                    Потом был VB (10-11класс) но использовал его крайне редко. видимо специфика писания в том возрасте мелких оконных «программ» по сути процедурного программирования.

                                                                                    а сейчас вот Ностольджы нахлынуло
                                                                                      +5
                                                                                      Единственное место где видел goto — драйвера. И то в очень маленьких дозах.
                                                                                      Обычно можно обойтись чем-нибудь вроде

                                                                                      do
                                                                                      {
                                                                                          ...
                                                                                          if(<error>)
                                                                                          {
                                                                                              ...
                                                                                              break;
                                                                                          }
                                                                                          ...
                                                                                      } while (false);


                                                                                      Против goto ничего не имею, однако и не фанатею. Если переходить, то только вниз по коду.
                                                                                        +5
                                                                                        Это тот же goto, только ещё и нарушающий семантику.
                                                                                        do {} while() — это цикл, у него семантика цикла. Когда я вижу do while я ожидаю увидеть цикл. А вы его используете как goto.
                                                                                        Это намного хуже, чем просто поставить одну несчастную метку «error:».
                                                                                          +5
                                                                                          Не то, чтобы я любитель этой конструкции, но это не «тот же goto». Отличие очевидно — goto может быть куда угодно и внезапно, в то время как с break всё понятно с областями видимости (scope), и про его возможность известно заранее, т.к. цикл. Это не делает while (false) красивым, тем не менее.
                                                                                        +10
                                                                                        Когда в коде есть goto — его намного сложнее векторизовать например для параллельной обработки, и прочие виды оптимизации.

                                                                                        Правило «goto-зло» имхо появилось не оттого, что оно действитльно зло, а потому, что в большой команде вместо того, чтобы каждому junior developer объяснять тонкости, проще его запретить и всем будет щастье
                                                                                          +3
                                                                                          Полностью согласен! На goto табу из-за того, чтобы начинающие лоб не расшибили — а опытные втихаря его используют, просто не афишируют
                                                                                        • UFO just landed and posted this here
                                                                                            0
                                                                                            Согласен, что компилятор предупредит ошибку.
                                                                                            А насчет того, что в Си++ goto нет места — не согласен, и я об этом уже написал — как Вы выйдете из глубин цикла, не выходя при этом из функции? Согласен, можно как-то переписать и выкрутиться, но иной раз это только лишь усложняет
                                                                                              0
                                                                                              Глубины цикла вообще плохо читаются.
                                                                                              • UFO just landed and posted this here
                                                                                                  +1
                                                                                                  из «глубин» можно бросить исключение, которое поймать на нужном уровне, сработает в аккурат как goto, но гарантирует корректность

                                                                                                  а вообще — слишком большие функции, особенно когда нужны такие выкрутасы с несколькими вложенными циклами — зло и надо дробить (с учетом inline — проигрыша не будет), там и без goto вникнуть будет тяжко
                                                                                                    +2
                                                                                                    Ога… и сразу возникает паттерн «реализация логики работы на исключениях». Круто, че!!!
                                                                                                      0
                                                                                                      Антипаттерн скорее…
                                                                                                        0
                                                                                                        Угу. Вообще использовать исключения для выхода из вложенных циклов это стрельба из пушки по воробьям. Они вообще для другого придуманы. Выход из вложенного цикла это штатная операция, а вовсе не исключительная ситуация.
                                                                                                          +1
                                                                                                          Что мешает сделать блок циклов отдельной функцией и использовать старый добрый return?
                                                                                                          По опыту — в большинстве случаев это можно сделать, а если действительно нельзя или слишком сложно — то такой код скорее всего пишет senior и он сможет корректно использовать тот же самый goto
                                                                                                            0
                                                                                                            Так и делаю обычно, причем функции еще можно inline'ить. Просто тут некоторые советуют исключениями кидаться, что вообще форменное безобразие. Исключение — это когда уже совсем капут и программа не может дальше выполняться нормально!
                                                                                                              0
                                                                                                              Точка зрения в том, что сам факт того, что требуется применять goto или исключения для выхода из цикла — совсем безобразие и лучше лечить первопричину.
                                                                                                                0
                                                                                                                Если речь обо мне (по поводу исключений) — это просто пример решения задачи без goto. Весьма корявый, как по мне. Но — зато без goto!
                                                                                                      0
                                                                                                      Поэтому во многих coding standarts запрещают больше 4-5 отступов — нужно пользоваться функциями и выходить из них.
                                                                                                    +1
                                                                                                    Мое мнение:
                                                                                                    goto нужен для оптимизации в кое каких местах, это очевидно. Читаемости кода с моей точки зрения (как человек мыслящий критериями ООП) он не очень способствует.

                                                                                                    Поэтому вывод:
                                                                                                    1) Использовать goto в рамке сложной программы нельзя.
                                                                                                    2) Использование goto выгодно когда требуется выполнить очень много однообразных операций, не выходящие за пределы одной процедуры, то есть в той процедуре где используется goto уже не должно вызываться других процедур.
                                                                                                      +9
                                                                                                      if(a==1)
                                                                                                      {
                                                                                                        A();
                                                                                                        C();
                                                                                                      }
                                                                                                      while(b!=0 && c!=1)
                                                                                                      {
                                                                                                        if(b==0)
                                                                                                        {
                                                                                                            D();
                                                                                                        }
                                                                                                        B();
                                                                                                        C();
                                                                                                      }
                                                                                                      E();
                                                                                                      

                                                                                                        0
                                                                                                        А где сказано, что A, B, C, D, E — это функции??? Это просто какие-то операции! И вполне возможно, что они используют массулокальных переменных! Обратите на это внимание!
                                                                                                        Только не надо мне предлагать в таком случае создание класса для их хранения…
                                                                                                          +8
                                                                                                          Функция с такой извращенной логикой и ещё с блоками кода, которые используют массу локальных переменных явно нуждается в рефакторинге.
                                                                                                            0
                                                                                                            А я честно и сразу написал в тексте, что не знаю, кому нужен такой бред!
                                                                                                            ДА и вообще — вот есть такая постановка задачи — и все тут! Надо реализовать! И как по мне — goto с этим справится лучше всего
                                                                                                              +4
                                                                                                              По вашему алгоритму, A,B,C и D это блоки операций, логичнее всего их выделить именно в функции, если они требуют каких то переменных для своей работы — передайте эти переменыне как аргументы. Выше написанный код действительно легко читается.
                                                                                                                0
                                                                                                                Возможно, что в качестве аргументов придется передавать все локальные переменные, да еще и по ссылке. Неэффективно…
                                                                                                                  0
                                                                                                                  Отож, и это раз.
                                                                                                                  Второе — тут многие (например, тут) goto заменяют copy-past — и это называется грамотным программированием?..
                                                                                                                    0
                                                                                                                    Вы рассуждаете о неэффективности несуществующей программы?
                                                                                                                    Некто Кнут говорил, что «Преждевременная оптимизация — корень всех зол».

                                                                                                                    Ну и есть же inline в этом вашем С++, если уж действительно оказалось неэффективно.
                                                                                                                      0
                                                                                                                      inline, насколько я помню, в plain-c отсутствует, кроме того inline — это РЕКОМЕНДАЦИЯ компилятору заинлайнить функцию, а не приказ.

                                                                                                                      Про Кнута, меня вот в последнее время веселит мания людей упоминать эту фразу. Оптимизация это когда изначально код хороший и четкий, но мы делаем из него быдлокод, чтобы оно быстрее работало. А сейчас это стали употреблять во всех случаях где надо и не надо. Допустим по алгоритму очевидно, что нужен контейнер с временем доступа O(1) и возможностью расширения. Ничто не мешает использовать vector, но люди воткнут list прикрываясь тем, что «преждевременная оптимизация — корень всех зол»

                                                                                                                      P.S. Лично я не согласен с конкретным примером топикстартера по использованию goto в данном случае.
                                                                                                                    0
                                                                                                                    Только зачем прямое сравнение с 0 и 1, когда в алгоритме этого нет.
                                                                                                                    Видимо, поэтому tzlom и не заметил, что
                                                                                                                    while( b && !c )
                                                                                                                    {
                                                                                                                    if( !b )… работать не будет.
                                                                                                                      –1
                                                                                                                      Отож! Я тоже почувствовал, что что-то не то в этом варианте, но не вникал. Хотя стоило бы…
                                                                                                                      А в варианте с goto — и вникать не надо. Логика работы очевидна!
                                                                                                                        +1
                                                                                                                        «Не то» здесь из-за кривой записи условий, а не отсутствия goto.

                                                                                                                        Пока код крошечный, ему и goto не страшен, потому что хорошо виден. А вот когда Вы развернёте все ваши A, B, C и так далее, да приправите «массой локальных переменных», тогда Вы и получите истинное пиршество для багов.
                                                                                                                        Вы некорректно привели пример, потому что скрыли в нём всё, что собственно и делает программу с goto нечитаемой.
                                                                                                                        0
                                                                                                                        Резонно, впрочем исправление не сложно
                                                                                                                        while(!(!b && c))
                                                                                                                          0
                                                                                                                          А почему не while(b || !c)?
                                                                                                                            0
                                                                                                                            на мой взгляд так легче понять что именно проверяет условие
                                                                                                                            я исходил из того что есть условие выхода, а в остальных случаях выполняется цикл
                                                                                                                  +6
                                                                                                                  А что вам мешает сделать их функциями? GOTO?
                                                                                                                  Да и замечу что дублируется только С так что проблема высосана из пальца
                                                                                                                  P.S.
                                                                                                                  очевидно что этот код гораздо читабельнее чем ваши гото
                                                                                                                  P.P.S.
                                                                                                                  zxm тоже правильные вещи пишет
                                                                                                                    0
                                                                                                                    Не хотите класс — создайте структуру. Масса локальных переменных — зло не меньшее, чем goto.
                                                                                                                    Если это — программа для микроконтроллера, то так и недо писать — для них правила другие.
                                                                                                                    А в обычных приложениях как данные, так и действия просто необходимо организовывать, тогда контролировать код будет намного легче, и костыли вроде goto не потребуются.
                                                                                                                    Я перестал использовать goto где-то в 1988 году и с тех пор желания вставить его куда-нибудь не возникало. Кстити, работал я тогда ещё на ЭВМ ЕС-1055.
                                                                                                                    +1
                                                                                                                    Не поленились разобрать первый пример =), завидую.
                                                                                                                    +2
                                                                                                                    Если вам кажется, что goto может улучшить код, то вы накосячили с архитектурой. В коротком коде еще можно изящно воспользоваться им, но если код достаточно сложен — ну его нафиг.
                                                                                                                      0
                                                                                                                      Что-то в последнее время большой приток алдековцев на Хабре :D

                                                                                                                      Хорошая статья!
                                                                                                                        0
                                                                                                                        Эх-х, давно я работал с VHDL — к сожалению, дальше теории дело не пошло. Попробовал на практике и ужаснулся — решил пользоваться ATmega и кучей обвязки…
                                                                                                                        +11
                                                                                                                        В прекрасной книге Макконнела «Совершенный код» есть почти целая глава, посвященная goto. Там очень доступно раскрываются плюсы и минусы. Перескажу её в трех тезисах:

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

                                                                                                                        2. Оператор goto КАК ПРАВИЛО увеличивает сложность кода. Переход непойми-когда непойми-куда непойми-зачем.

                                                                                                                        3. В тех редких случаях, когда goto уменьшает сложность — его МОЖНО и НУЖНО использовать. Но нужно быть четко уверенным, что его применения оправдано.

                                                                                                                        Как и любой другой инструмент, goto бывает в тему, а бывает нет. Головой думать надо.
                                                                                                                          0
                                                                                                                          Сталкивался с доводкой под современные нужды программ написанных на старых реализациях fortran-а. Чёрт ногу сломит в старых конструкциях, когда использование GOTO было явным (кто видел, тот поймёт. Кто не видел — советую посмотреть занимательные / 15 do 21 сТЕЛО 21 GOTO 15 /).

                                                                                                                          Сейчас это (вредность) конечно не так актуальна, и я соглашусь с автором — подчас использовать GOTO проще и информативнее.
                                                                                                                            +1
                                                                                                                            Вот из за таких фортрановских прог Дейкстра и начал свою войну с goto
                                                                                                                            +10
                                                                                                                            Использовать goto — это как переходить дорогу в неправильном месте. Вроде можно успеть, но шанс быть сбитым значительно выше.
                                                                                                                            Код функции, цикла можно свернуть и оставить короткий кометарий. Блок с goto как сворачивать непонятно. И не понятно, какой уровень сложности там в конце концов окажется. В конце коцов человек возьмет карандаш, бумагу и начнет чертить для себя схему работы этого goto коммутатора.
                                                                                                                            goto — игра в наперсток.
                                                                                                                            P.S. За статью все равно спасибо. Существует много догм в программировании, которые надо пересматривать.
                                                                                                                              +1
                                                                                                                              В далекие 90-е моя учительница по Basic говорила что «чем больше операторов GOTO в программе тем ниже квалификация программиста».
                                                                                                                                +2
                                                                                                                                А до нее — Эдсгер Вибе Дейкстра
                                                                                                                                  0
                                                                                                                                  В смысле, тем низкоуровневее он программирует? :)
                                                                                                                                    0
                                                                                                                                    Чем она предлагала пользоваться?
                                                                                                                                    +4
                                                                                                                                    В С++ ситуацию я не готов комментировать с достаточным основанием, но все же стоит сначала понять, что алгоритм должен делать и лишь потом переходить к его кодированию. Это вообще, общий совет. Сначала надо понять, что ты делаешь, а вот тогда и выяснится, что высокоуровневые примитивы лучше описывают задачу. Я не беру ситуацию низкоуровневой оптимизации, которая как понятно никогда не должна быть преждевременной.

                                                                                                                                    В современных язык очень не любят goto из очень простых соображений, высокоуровневые примитивы предсказуемы. Точка входа в for, while, if предсказуема и понятна. Точка входа в for это строчка которая находится перед этим самым циклом. Да, внутри цикла переходы будут посложнее, но опять же и тут это предсказуемые и однотипные переходы. В случае с метками, никогда не поймешь откуда произошел переход на нее, пока не просмотришь ВЕСЬ код. Теряется свойство локальности, инкапсуляция кода.

                                                                                                                                    Аналогичная беда есть с эксепшенами, но и там как бы контрол флоу предсказуем относительно, хоть и требует некоторого навыка, ибо он неявен. Но все равно в целом контроль над переходами остается. В случае с goto же получается полная каша, глядя на метку невозможно понять откуда на нее попробует код перескочить.
                                                                                                                                      +1
                                                                                                                                      То-ва-ри-щи! Ну кто — кто призывает Вас лепить goto повсюду по поводу и без повода?!?!? Использование goto в С и тем более С++ — достаточно редкая и даже исключительная ситуация! Но такая ситуация встречается! И вот эти ситуации надо четко выделять, рассказывать начинающим и учить их: «goto использовать крайне не рекомендуется. Но есть несколько ситуаций, где он нужен — это 1)… 2)… и 3)… В других случаях его лучше избегать, поскольку можно заменить 1)… 2)… и 3)… ».
                                                                                                                                      Вот и все!
                                                                                                                                        0
                                                                                                                                        В языках с перегружаемыми функциями (в java вон вообще по умолчанию функции виртуальные), это ощущение контроля тут же теряется — при вызове функции далеко не всегда известно, куда понесёт и что оттуда вернётся. Да и сама суть полиморфизма в этом, так что не факт что именно это основная проблема.
                                                                                                                                          0
                                                                                                                                          Да, что хорошо, про Яву мне говорить попроще. Действительно вызов функции может привести к очень не очевидным действиям, особенно, если у нас вызов идет через динамический контейнер (пикоконтейнер, например), еще и используя reflection. Но, эту сложность и хитрость специальным образом обертывают в предсказуемые высокоуровневые концепции, это либо библиотека-контейнер, которой надо довольно долго учится и понимать ее, либо просто стандартные концепции Явы. Это не тот беспредел, который вносит goto. Это высокоуровневый контракт, в который и выносят всю сложность этого типа. У exceptions есть схожие проблемы. Как раз основная идеология, это собрать все сложные места и вынести их в небольшое ядро и обеспечить некой предсказуемой идеологией. С goto проблема в том, что в каждом месте, где оно будет использоваться, это будет свой способ, за этим будет своя логика, свои переходы итп.

                                                                                                                                          Аналогичный подход используется в многопоточных штуках всяких, когда всю многопоточную специфику уносят в ядро, где обеспечивают корректные передачи объектов, понятные контракты итп. При этом отсальной код пользуясь некоторым набором высокоуровневых правил может не заботится изза многопоточки.
                                                                                                                                        0
                                                                                                                                        Не понимаю весь вводный опус по поводу языка ассемблера. Если говорить честно, то кроме условных и безусловных переходов там вообще нет функций управления потоком выполнения (разве что call и retn). Никаких готовых циклов и if. Я к тому, что если кодить на асме, то использование jXX (прямого аналога goto/if+goto) — единственная возможность реализации условий и прочего.
                                                                                                                                        А так да, если использовать goto умерено и не прыгать в центр блоков кода — то это может гораздо уменьшить объём кода, увеличить читаемость и как следствие уменьшить количество багов. Особенно часто goto хорош если в конце процедуры нужно выполнить несколько заключительных действий (закрыть файлы/освободить память) и только после этого выйти, а точек выхода из самого алгоритма несколько (примерно как в последнем примере). Можно использовать для этого exception'ы, но на мой взгляд такие извращения только для тех языков, в которых нет goto (например Python).
                                                                                                                                        • UFO just landed and posted this here
                                                                                                                                            +5
                                                                                                                                            Пример изначально надуманный.

                                                                                                                                            Как сказал один мой знакомый:
                                                                                                                                            Автор нарисовал блок-схему с конкретными хомутами, и показал, что гоу ту применим в таких случаях. имхо, если в приложении дошли до таких изворотов в логике, то там уже пох на всё и можно писать все что угодно, goto тоже )
                                                                                                                                              +4
                                                                                                                                              Я вам могу привести реальный пример на си. Как вы знаете, в большинстве случаев сишные функции в качестве результата возвращают ноль или код ошибки. Допустим вам надо сделать последовательный вызов 10 функций, причем каждая последующая вызывается только после успешного окончания предыдущей. В случае неуспеха надо допустим вернуть номер упавшей функции по порядку.
                                                                                                                                              Код без goto
                                                                                                                                              if(!func1(...))
                                                                                                                                              {
                                                                                                                                                if(!func2(...))
                                                                                                                                                {
                                                                                                                                                   .....
                                                                                                                                                 }
                                                                                                                                                 else
                                                                                                                                                 {
                                                                                                                                                  code = 2
                                                                                                                                                 }
                                                                                                                                              }
                                                                                                                                              else
                                                                                                                                              {
                                                                                                                                              code = 1
                                                                                                                                              }
                                                                                                                                              


                                                                                                                                              Случай с гото
                                                                                                                                              if(func1(...))
                                                                                                                                              {
                                                                                                                                              code = 1;
                                                                                                                                              goto exit;
                                                                                                                                              }
                                                                                                                                              if(func2(...))
                                                                                                                                              {
                                                                                                                                              code = 2;
                                                                                                                                              goto exit
                                                                                                                                              }
                                                                                                                                              ...
                                                                                                                                              exit:
                                                                                                                                              return code;
                                                                                                                                              


                                                                                                                                              Также учтите, что в exit может стоять освобождение выделенных в куче ресурсов, а с множеством return'ов вам это освобождение придется вписывать везде.

                                                                                                                                              В общем я за гото именно в таких случаях, поскольку он упрощает код и облегчает его понимание. Но безусловно я против, когда гото используется просто потому, что «программист» не может описать свою задачу алгоритмически. И повторюсь, это для си, в плюсах естественно все по-другому.
                                                                                                                                                +2
                                                                                                                                                Можно последовательные вызовы функций унести в отдельную функцию, использовать return, а выделение и чистку ресурсов сделать в обертке.
                                                                                                                                                  0
                                                                                                                                                  Да, вы правы, можно и в обертке, но только это лишнее усложнение кода, поскольку создается функция, которая в принципе не нужна. Ну и ко всему прочему вызов функции все-таки немного помедленнее безусловного перехода. Это как в тройном вложенном цикле, можно тупо goto, а можно наворотить кучу флагов и ненужных проверок.
                                                                                                                                                    +1
                                                                                                                                                    inline-вызов функции у хорошего компилятора никак не медленнее чем обычный переход ;)
                                                                                                                                                      0
                                                                                                                                                      Охх, «лишнее усложнение кода» — это как раз лапшевидные goto. Главное это всё же чтобы код легко поддерживался, т.е. легко читался. Вызов функции совсем не обязательно медленнее, уже очень давно компилятор нужно отдельно заставлять, чтобы он не инлайнил функции. И это ещё умудриться надо заставить, потому что в отдельных случаях эта сволочь ;) заинлайнит функции, которые казалось бы вообще нельзя (link-time optimization). Вообще, говорить что-то о производительности без тестов (к тому же грамотных) — гиблое дело.
                                                                                                                                                      0
                                                                                                                                                      Это как раз правильный C++ way, автор же больше на си напирает :)
                                                                                                                                                      0
                                                                                                                                                      if( func1(...) )
                                                                                                                                                      {
                                                                                                                                                          code = 1;
                                                                                                                                                      }
                                                                                                                                                      else if( func2(...) )
                                                                                                                                                      {
                                                                                                                                                          code = 2;
                                                                                                                                                      }
                                                                                                                                                      ...
                                                                                                                                                      return code;
                                                                                                                                                        0
                                                                                                                                                        А если между вызовами нужно делать еще какие-то операции? например печатать в лог?
                                                                                                                                                          +1
                                                                                                                                                          if( !code && func1(...) )
                                                                                                                                                          {
                                                                                                                                                              code = 1;
                                                                                                                                                          }
                                                                                                                                                          if( !code && func2(...) )
                                                                                                                                                          {
                                                                                                                                                              code = 2;
                                                                                                                                                          }
                                                                                                                                                          ...
                                                                                                                                                          return code;


                                                                                                                                                          А вообще, для этого в с++ есть исключения
                                                                                                                                                            0
                                                                                                                                                            Ах, простите, вы про си писали…
                                                                                                                                                              0
                                                                                                                                                              Ну вообще я написал, что это С.

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

                                                                                                                                                              Все жа наиболее равнозначной заменой будет функция-обертка, но это уже лишнее усложнение.
                                                                                                                                                                0
                                                                                                                                                                Для си я с вами согласен, невнимательно прочитал…

                                                                                                                                                                Для с++ лучше все-таки обходится без goto (если это не усложняет восприятие чрезмерно), потому как деструкторы и конструкторы. Бывают, конечно, случаи… но редко.
                                                                                                                                                          0
                                                                                                                                                          code = 0;
                                                                                                                                                          if (!func1(...)){
                                                                                                                                                          code =1;
                                                                                                                                                          }

                                                                                                                                                          if (!code){
                                                                                                                                                          if (!func2(...)){
                                                                                                                                                          code =2;
                                                                                                                                                          }
                                                                                                                                                          }

                                                                                                                                                          if (!code){
                                                                                                                                                          if (!func3(...)){
                                                                                                                                                          code =3;
                                                                                                                                                          }
                                                                                                                                                          }

                                                                                                                                                          ...

                                                                                                                                                          return code;
                                                                                                                                                            0
                                                                                                                                                            Куча лишних ненужных проверок
                                                                                                                                                              0
                                                                                                                                                              Никто не говорит, что в высокоуровневых языках надо использовать goto. Для конкретно моего случая там есть исключения и функции возвращают обычно результат, а не код ошибки. Но на plain-c это по-моему наиболее удобный и быстрый способ.
                                                                                                                                                                0
                                                                                                                                                                Вы привели пример падения читаемости кода без использования goto, я показал, как можно обойтись без него и сохранить читаемость кода, приближенную к исходной. А если заменить название переменной с code на error, то еще и по фрагменту текста станет понятно, что мы не вызываем func_n+1, если у нас уже случилась ошибка. Вариант с goto не объясняет нам, почему мы делаем переход.
                                                                                                                                                                Если говорить о ненужности проверок с точки зрения скорости выполнения кода — без контекста это будет преждевременной оптимизацией.
                                                                                                                                                                  +1
                                                                                                                                                                  Вопрос, а зачем это было делать, если goto уже обеспечивает отличную читаемость да и в принципе должен быть оптимальным по количеству инструкций? Из каких-то религиозных соображений? Так вот про этим самые религиозные соображения и говорил ТС и я с ним согласен.
                                                                                                                                                                    0
                                                                                                                                                                    Тут скорее другое. Меня учили программировать без goto, но этот оператор рвотного рефлекса у меня не вызывает.
                                                                                                                                                                    Если вариант без goto будет страшен как смертный грех — поставить goto рука не дрогнет. Описанную же Вами задачу я бы, скорее всего, решил так как написал, т.е. с проверку на возникновение ранее ошибки.
                                                                                                                                                                    +1
                                                                                                                                                                    Кроме того, если между операциями надо что-то делать, причем только если операция была успешной, то у вас добавится еще куча условий. И ради чего все это? Ради того, что какой-то дядя сказал, что goto плохо и не надо его использовать вообще никогда?
                                                                                                                                                                      0
                                                                                                                                                                      В моем примере if резделены, т.е. один на проверку отсутствия ошибки, а вложенный обрабатывает возврат и текущей функции. С

                                                                                                                                                                      если между операциями надо что-то делать, причем только если операция была успешной


                                                                                                                                                                      проблем не вижу.

                                                                                                                                                                      И я не говорю про то, что goto следует выбросить из языка. Я говорю про то, что в конкретном, приведенном Вами примере можно обойтись без goto и не потерять в производительности.
                                                                                                                                                                0
                                                                                                                                                                if(!func1(...))
                                                                                                                                                                {
                                                                                                                                                                return 1;

                                                                                                                                                                }
                                                                                                                                                                if(!func2(...))
                                                                                                                                                                {
                                                                                                                                                                return 2;
                                                                                                                                                                }

                                                                                                                                                                  –1
                                                                                                                                                                  return из глубины функции это тот же слегка замаскированный goto. И даже в чём-то хуже — например, поставить брейкпоинт на выходе из функции оказывается нетривиально и чревато ошибками.

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

                                                                                                                                                                    А разбивание на под задачи это даже хорошо чем куча не управляемых меток.
                                                                                                                                                                    За весь не большой опыт не разу не было случая когда не то что стояла острая необходимость в goto, а даже малейшего намека на это. Я о нем даже и не вспоминаю.
                                                                                                                                                                  0
                                                                                                                                                                  О, вот оно и есть то самое! Полностью согласен с комментарием!
                                                                                                                                                                    0
                                                                                                                                                                    Как правило такой код можно разбить на несколько логических блоков типа инициализация, основная работа, освобождение ресурсов и эти логические блоки реализовать в виде отдельных функций. Все лучше чем ваша простыня.
                                                                                                                                                                      0
                                                                                                                                                                      Ага, и каждый из таких логических блоков будет в качестве результата возвращать код ошибки. Таков уж стиль С и такие ситуации в С -программировании встречаются весьма и весьма часто.

                                                                                                                                                                      А по поводу освобождения ресурсов. Где-то слышал мнение о том, что в идеале программа на С должна освобождать выделенную память в том же логическом блоке, в котором она была выделена. В противном случае вы можете долго и непринужденно ловить утечки памяти. Ну исключением из этого правила являются разве что аллокаторы, но это отдельная песня. Это в java можно создать объект и вернуть ссылку на него, авось GC потом разберется. А в си надеяться на то, что вызывающий код освободит выделенную в данной функции память не стоит.
                                                                                                                                                                        +1
                                                                                                                                                                        >> Ага, и каждый из таких логических блоков будет в качестве результата возвращать код ошибки
                                                                                                                                                                        И в чем проблема?

                                                                                                                                                                        >> А в си надеяться на то, что вызывающий код освободит выделенную в данной функции память не стоит.
                                                                                                                                                                        Ересь какая-то. Что значит не стоит надеятся? Вы же не в рулетку играете. Есть контракт, его несоблюдение это ошибка, да.
                                                                                                                                                                        Интересно, у Кернигана была хоть маленькая надежда что вы free вызовете после malloc? :)
                                                                                                                                                                          0
                                                                                                                                                                          1. А то, что в вышестоящей функции вам так же придется обрабатывать эти коды после каждого блока

                                                                                                                                                                          2. free и malloc это низкоуровневые инструменты. Это и есть те самые аллокаторы, о которых я писал, но это не значит, что каждая вторая функция должна выделять память и возвращать указатель на нее. Вот это уже будет похлеще goto, программа вроде работает и правильно работает, но блин память потихоньку куда-то девается

                                                                                                                                                                          3. А про Кернигана это вообще смешно. Как будто у создателя молотка есть надежда, что пользователь этого молотка не треснет себе по пальцам? Однако же при работе с молотком есть такая вещь как техника безопасности, в которой явно указывается, что по пальцам себе бить не стоит. Не, вы конечно можете это сделать, но это будут уже сугубо ваши проблемы.
                                                                                                                                                                      0
                                                                                                                                                                      Всегда для этого делал:
                                                                                                                                                                      do {

                                                                                                                                                                      if( func1(...) ) {
                                                                                                                                                                      code = 1;
                                                                                                                                                                      break;
                                                                                                                                                                      }

                                                                                                                                                                      if( func2(...) ) {
                                                                                                                                                                      code = 2;
                                                                                                                                                                      break;
                                                                                                                                                                      }

                                                                                                                                                                      ...
                                                                                                                                                                      } while( 0 );

                                                                                                                                                                      И горя не знал ;)
                                                                                                                                                                        0
                                                                                                                                                                        А если у Вас внутри будет вложенная конструкция? Там уже нужно несколько break
                                                                                                                                                                          0
                                                                                                                                                                          Не без этого. Но всё же лично я предпочту в 90% написать без goto. Почему? — этот код может потом править другой человек, где уверенность, что он также учтёт все возможные проблемы?
                                                                                                                                                                      0
                                                                                                                                                                      Да, алгоритм надуманный. НО — может случиться в реальной жизни! На нем я показал, как goto-боязнь заставляет делать сложный и малопонятный код.
                                                                                                                                                                      А алгоритм был придуман, кстати, под воздействием температуры 38.3…
                                                                                                                                                                      +1
                                                                                                                                                                      google и qt не используют исключения.
                                                                                                                                                                      и?

                                                                                                                                                                      и ничего.
                                                                                                                                                                      просто одним инструмент подходит, другим нет.

                                                                                                                                                                      также и с goto.

                                                                                                                                                                      можно/нельзя — это не тот вопрос, который нужно задавать.

                                                                                                                                                                      оправдано/не оправдано использование в каждом конкретном случае — вот это правильный вопрос.
                                                                                                                                                                        +1
                                                                                                                                                                        char a, b, c;

                                                                                                                                                                        for (a = 0; a < 10; ++a)
                                                                                                                                                                        {
                                                                                                                                                                        for (b = 0; b < a; ++b)
                                                                                                                                                                        {
                                                                                                                                                                        if (!c)
                                                                                                                                                                        goto Leave;
                                                                                                                                                                        }
                                                                                                                                                                        for (b = 10; b < 15; ++b)
                                                                                                                                                                        {
                                                                                                                                                                        d ();
                                                                                                                                                                        }
                                                                                                                                                                        }

                                                                                                                                                                        Leave:
                                                                                                                                                                        e ();


                                                                                                                                                                        а вот так разве не лучше?

                                                                                                                                                                        void task()
                                                                                                                                                                        {
                                                                                                                                                                        char a, b, c;

                                                                                                                                                                        for (a = 0; a < 10; ++a)
                                                                                                                                                                        {
                                                                                                                                                                        for (b = 0; b < a; ++b)
                                                                                                                                                                        {
                                                                                                                                                                        if (!c) return;
                                                                                                                                                                        }
                                                                                                                                                                        for (b = 10; b < 15; ++b)
                                                                                                                                                                        {
                                                                                                                                                                        d ();
                                                                                                                                                                        }
                                                                                                                                                                        }
                                                                                                                                                                        }
                                                                                                                                                                        ...

                                                                                                                                                                        task();
                                                                                                                                                                        e ();
                                                                                                                                                                          0
                                                                                                                                                                          А где же выполнение e() перед выходом?
                                                                                                                                                                            +1
                                                                                                                                                                            сразу после task();
                                                                                                                                                                              0
                                                                                                                                                                              Да, разобрался, увидел.
                                                                                                                                                                              Как по мне — мой вариант читабельнее и вопросов не создает
                                                                                                                                                                            0
                                                                                                                                                                            Так хуже, непонятнее и фрагментарнее. Особенно если вспомогательной функции приходится передавать мешок параметров.
                                                                                                                                                                              0
                                                                                                                                                                              Ага, и особенно надо помнить о конструкторах копирования, правах const и тому подобном…
                                                                                                                                                                            0
                                                                                                                                                                            А теперь посмотрим на хитровывернутый алгоритм. Представление не имею что это за бред – но его надо реализовать.


                                                                                                                                                                            Что значит «представления не имею, что это за бред»? А как же анализ ТЗ?
                                                                                                                                                                              0
                                                                                                                                                                              Шутка юмора. И намек на то, что не нужно рассматривать данный пример на реальность, рефакторинг и т. п. А взять его как данность — этот алгоритм — и попробовать реализовать
                                                                                                                                                                              0
                                                                                                                                                                              «А то, что не-использование goto не застрахует Вас от неправильно написанной программы. Так же и применение его не гарантирует, что программа будет сыпаться. Нужно писать программы с умом и не делать таких элементарных глюков.»

                                                                                                                                                                              Из этих строчек у меня складывается впечатление, что статья ни о чём. То что вы пишите, и так понятно.
                                                                                                                                                                                +2
                                                                                                                                                                                Это не всем понятно. goto is evil — это догма. Для многих эта догма является непререкаемой истиной, вон посмотрите сколько таких в комментариях.
                                                                                                                                                                                Эта статья напоминает, что программирование должно быть основано на логике, а не на догмах.
                                                                                                                                                                                +2
                                                                                                                                                                                Begin
                                                                                                                                                                                L1:
                                                                                                                                                                                If (goto нужен) goto L2
                                                                                                                                                                                L2:
                                                                                                                                                                                If (goto не нужен) goto L1
                                                                                                                                                                                End.
                                                                                                                                                                                  0
                                                                                                                                                                                  Хорошая статья, для «новичков в этом мире программирования» как я, это хороший пример что goto всё-равно лучше не использовать, но из тысячи функций, в одной может оказаться так что goto будет лучше и красивее и даже читабельнее.
                                                                                                                                                                                  Но это крайне редкий случай.
                                                                                                                                                                                    0
                                                                                                                                                                                    Программируете с 7 лет? Авторитееет!!! (я бы вот постеснялся так считать сколько я программирую). В языках высокого уровня goto — ересь и она должна быть уничтожена вместе с носителем.
                                                                                                                                                                                      0
                                                                                                                                                                                      В вашем примере с циклами всё решается:

                                                                                                                                                                                      char a, b, c;

                                                                                                                                                                                      for (a = 0; a < 10; ++a)
                                                                                                                                                                                      {
                                                                                                                                                                                      for (b = 0; b < a && c; ++b) {}

                                                                                                                                                                                      if (!c) { break; }

                                                                                                                                                                                      for (b = 10; b < 15; ++b)
                                                                                                                                                                                      {
                                                                                                                                                                                      d ();
                                                                                                                                                                                      }
                                                                                                                                                                                      }

                                                                                                                                                                                      e ();

                                                                                                                                                                                      Но вообще такое попадалось максимум раза 3, но решал всегда без goto. Лично я его не использовал, так как нигде не видел в нём особой нужды.
                                                                                                                                                                                        +2
                                                                                                                                                                                        Вспомнил интересную историю связанную с goto. После того, как Дейкстра опубликовал свою статью Go To Statement Considered Harmful один из разработчиков фортрана Лоренс Кларк предложил, раз уж пользоваться goto плохо, ввести новый оператор COMEFROM. В операторе COMEFROM указывалась метка при достижении которой управление должно переходить на соответствующий оператор COMEFROM.
                                                                                                                                                                                        www.fortran.com/fortran/come_from.html
                                                                                                                                                                                          –1
                                                                                                                                                                                          Знаете, пришлось недавно по учёбе писать лабы для некоего контроллера Мега (не знаю, что за девайс такой и чьего он производства). Но у него свой ассемблер, в котором нет даже GOTO. Программа — один большой цикл и из всех условных команд есть только SET и RST (устанавливающие и сбрасывающие определённый регистр только если значение регистра-аккумулятора истинно).
                                                                                                                                                                                          Я молил небо о том, чтобы оно мне ниспослало ХОТЯ БЫ goto )))
                                                                                                                                                                                            0
                                                                                                                                                                                            может ATmega?
                                                                                                                                                                                              0
                                                                                                                                                                                              Нет, это не Atmel, у тех вполне вменяемый ассемблер (а на AVR32 можно и на C и на C++ писать).
                                                                                                                                                                                              +1
                                                                                                                                                                                              в ассемблере не было безусловных переходов? Подробнее.
                                                                                                                                                                                                0
                                                                                                                                                                                                Да, как-то фантастически звучит… Может, речь о DPS-контроллерах?
                                                                                                                                                                                                  0
                                                                                                                                                                                                  Хм… моих познаний явно не достаточно, или вы, в свою очередь, имели ввиду DSP? Но на сколько я знаю, там тоже есть переходы и ассемблер под них достаточно сложен
                                                                                                                                                                                                    +1
                                                                                                                                                                                                    Приходилось писать под DSP Texas Intruments 6200. Жестокая вещь. Jmp там, конечно, есть (более того — нет ни call, ни return — все приходится писать через jmp). Но проблема в том, что этот jmp срабатывает только через 5 команд, после того, как он написан! Т.е. пишется

                                                                                                                                                                                                    jmp X1
                                                                                                                                                                                                    cmd1
                                                                                                                                                                                                    cmd2
                                                                                                                                                                                                    cmd3
                                                                                                                                                                                                    cmd4; только в этот момент сработал jmp
                                                                                                                                                                                                    X2:

                                                                                                                                                                                                    Зато там выполнение любой команды можно сделать условным. Есть несколько регистров (3 или 5), которые можно использовать в кажестве флажка — выполнять команду (в том числе, jmp) только при условии, что регистр равен нулю или при условии, что он нулю не равен. Очень эффектно выглядят циклы, начинающиеся с jmp на себя:

                                                                                                                                                                                                    X1: [B0] jmp X1
                                                                                                                                                                                                    sub B0,1,B0


                                                                                                                                                                                                    Если добавить, что там 8 логических устройств, работающих параллельно, но команды для них надо указывать явно (т.е. одна команда может занимать до 8 строчек кода), все становится еще веселее. К сожалению, ощутить это дело в полной мере пока не удалось.
                                                                                                                                                                                                      0
                                                                                                                                                                                                      Мда-а, хорошо, что я еще не программировал под них! Банальный ATmega — все просто!
                                                                                                                                                                                                        0
                                                                                                                                                                                                        Да, это дзен.
                                                                                                                                                                                                        0
                                                                                                                                                                                                        Ой-й, ну да, DSP…
                                                                                                                                                                                                      0
                                                                                                                                                                                                      Там какой-то учебный контроллер. 16 дискретные входов, 16 выходов, аналоговые входы, регистры, таймеры и ячейка-аккумулятор, именно с которой и работают почти все команды. Например AND X00 производит логическое И аккумулятора с дискретным входом 0 и помещает результат в аккумулятор. Немножко расширяет сознание, разбалованное питоном с его вкусностями :-)
                                                                                                                                                                                                        0
                                                                                                                                                                                                        Ну по описанию это мелкие AVR\PIC-подобные контроллеры, но что б у них не было goto…
                                                                                                                                                                                                    0
                                                                                                                                                                                                    Кстати, табу на goto появилось вроде бы в рамках структурного программирования. Т.е. программирования доказательного.
                                                                                                                                                                                                      0
                                                                                                                                                                                                      А как насчет comefrom? :)
                                                                                                                                                                                                        0
                                                                                                                                                                                                        За последние десять лет ни разу не писал goto, вот как с TurboBasic'а ушел, так и не пользуюсь =)
                                                                                                                                                                                                          +3
                                                                                                                                                                                                          Это ваше goto напоминает ссылки в законодательных актах. Типа пункт 1.3 — см постановление №13747 от 13.10.2003, а там еще куча таких же ссылок. И вроде хотел по законодательству посмотреть — что да как делать, а в итоге тратишь час на разбирание этой лапши. Юристам, которые в договорах делают ссылки между пунктами — руки бы поотрывал.

                                                                                                                                                                                                          Все хорошее хорошо в меру. И если использование оправдано, то почему нет, а если оно только усложняет понимание и весь процесс — то в топку такие штуки. KISS.
                                                                                                                                                                                                            +2
                                                                                                                                                                                                            Полностью согласен с автором. Даже в java не смотря на все его многочисленные запреты, в угоду стабильности, сохранились метки и операторы очень напоминающие GOTO. Вот только объявлять и использовать их можно только внутри одной функции, что с моей точки зрения абсолютно правильно. А вообще чтобы избавиться от предрассудков всем рекомендую немного по программировать на Ассемблере.
                                                                                                                                                                                                              0
                                                                                                                                                                                                              Так то оно так. Когда я писал на Си драйвер, метки с goto сами собой как-то напрашивалиь :) Программируя на java ужн года 2 так и не разу не было случая, что бы нужен был goto. К примеру в случае в выходом из вложенных циклов: обычно я такие штуки в отдельный метод выношу.
                                                                                                                                                                                                                0
                                                                                                                                                                                                                А вот в Tcl команды goto нету. Как, впрочем, и в лиспах всевозможных, насколько правильно я помню.
                                                                                                                                                                                                              • UFO just landed and posted this here
                                                                                                                                                                                                                • UFO just landed and posted this here
                                                                                                                                                                                                                  0
                                                                                                                                                                                                                  Слышал мнение, что оптимизатор компилятора плохо работает с goto. Кто-то может прокомментировать?
                                                                                                                                                                                                                    0
                                                                                                                                                                                                                    Бывает, что компилятор «разворачивает» некоторые циклы в целях оптимизации, или меняет порядок команд без изменения логики работы. Если в этом месте присутствует goto и метки для него, то он ничего менять не станет, ибо логика может нарушится. В большинстве случаев компиляторы справляются и никаких проблем не возникает.
                                                                                                                                                                                                                    0
                                                                                                                                                                                                                    Холивар с goto же Виртом был разведен? Ну дак там же и цели были другие — обучение студентов культуре программирования.
                                                                                                                                                                                                                      +1
                                                                                                                                                                                                                      Дейкстрой
                                                                                                                                                                                                                      +1
                                                                                                                                                                                                                      Использую goto только для выхода из вложенных циклов, в остальном стараюсь обходиться без него.
                                                                                                                                                                                                                        +1
                                                                                                                                                                                                                        Обычно можно такой код вынести в подпрограмму. Попробуйте. ИМХО — это решение еще более читабельно, чем goto. Флажки — вот это точно полный бред.
                                                                                                                                                                                                                          0
                                                                                                                                                                                                                          Когда после goto ещё много всего, то так и делаю. А ради пары строк кода плодить новые функции с дурацкими именами (просто осмысленные названия таким функциям тяжело придумать) не очень то хочется.
                                                                                                                                                                                                                        +4
                                                                                                                                                                                                                        Мне кажется, что полезность goto в мире C++ значительно ниже, чем в мире C.

                                                                                                                                                                                                                        1. Дело даже не в пресловутых исключениях. Например, я не считаю, что использование исключений для выхода из вложенного цикла оправданно. Думаю, что killer-feature, делающая goto малополезной это автоматический вызов деструкторов созданных объектов.

                                                                                                                                                                                                                        Рассмотрим один из примеров испол