goto statement in C#
This basically counts the number and if the i is greater than 20 it should not write to console.writeline. it should step over and hit «out1» but the «out1» needs to have a function in the end to compile. It needs to have «string hello = «»» to compile. I don’t need the «string hello = «»». I just want it to do nothing and got the end of the loop. Is there a way to do this without the «string hello = «»» that the out1: statement needs? Like:
6 Answers 6
Though it is absolutely correct to say that there are better ways to solve this problem than to use goto, I note that no one has actually answered your question.
A label must label a statement. You want to go to a location that has no statement associated with it. You can either make an empty statement with a single semicolon, or an empty block.
But like they say, don’t go there in the first place if you can avoid it.
This loop could easily be written many other ways — you could just loop while i<=20 instead of i<40 (best), or move the Console.WriteLine call into the if statement with the if inverted.
However, I’m assuming you’re trying to work with a more elaborate scenario in your «real» case. If that’s the case, instead of using goto , just use continue to skip the rest of the loop:
Similarly, you can use break to completely break out of the loop and not process more elements, if that’s more appropriate in your real case.
Оператор goto в C++
В этой статье вы узнаете об операторе goto, о том, как он работает и почему его следует избегать.
В программировании на C++ оператор goto используется для изменения нормальной последовательности выполнения программы путем передачи управления какой-либо другой части программы.
Синтаксис оператора goto
В приведенном выше синтаксисе метка – это идентификатор. Когда goto label встречается, управление программой переходит к метке и выполняет код под ней.

Пример
Вы можете написать любую программу на С++ без использования оператора goto.
Причина, по которой следует избегать использования goto
Оператор goto дает возможность перейти к любой части программы, но делает программу сложной и запутанной.
В современном программировании оператор goto считается вредной конструкцией и плохой практикой программирования. Оператор goto можно заменить в большинстве программ на C++ с помощью операторов break и continue.
Операторы перехода
Язык C# предлагает несколько операторов, позволяющих немедленно перейти на другую строку программы.
К ним относятся четыре оператора: goto (go to — «перейти к»), break (перерыв), continue (дальше), return (возврат).
Конечно, самой плохой репутацией пользуется оператор goto, однако он сохранен в языке C#. Я иногда использую его при отладке программ (например, для обхода части кода), главное — не забыть его потом удалить. Другая (не слишком уважительная) причина — обеспечение преемственности с языками C и C++.
Рассмотрим их подробнее.
Оператор goto
Имеющийся в C# оператор goto представляет собой оператор безусловного перехода.
Когда в программе встречается оператор goto, ее выполнение переходит непосредственно к тому месту, на которое указывает этот оператор.
Он уже давно «вышел из употребления» в программировании, поскольку способствует созданию «макаронного» кода.
Хотя в некоторых случаях он оказывается удобным и дает определенные преимущества, если используется благоразумно.
Главный недостаток оператора goto с точки зрения программирования заключается в том, что он вносит в программу беспорядок и делает ее практически неудобочитаемой.
Но иногда применение оператора goto может, скорее, прояснить, чем запутать ход выполнения программы.
Для выполнения оператора goto требуется метка — действительный в C# идентификатор с двоеточием. Метка должна находиться в том же методе, где и оператор goto, а также в пределах той же самой области действия.
Пример использования оператора goto:

Репутация оператора goto такова, что в большинстве случаев его применение категорически осуждается. Вообще говоря, он, конечно, не вписывается в рамки практики ООП и применять его не рекомендуется.
Оператор break
С помощью оператора break можно специально организовать немедленный выход из цикла в обход любого кода, оставшегося в теле цикла, а также минуя проверку условия цикла.
Когда в теле цикла встречается оператор break, цикл завершается, а выполнение программы возобновляется с оператора, следующего после этого цикла.
Оператор break можно применять в любом цикле, предусмотренном в C#.
Пример:

Обратите внимание, что если оператор break применяется в целом ряде вложенных циклов, то он прерывает выполнение только самого внутреннего цикла.
В отношении оператора break необходимо также иметь в виду следующее.
Во-первых, в теле цикла может присутствовать несколько операторов break, но применять их следует очень аккуратно, поскольку чрезмерное количество операторов break обычно приводит к нарушению нормальной структуры кода.
И во-вторых, оператор break, выполняющий выход из оператора switch, оказывает воздействие только на этот оператор, но не на объемлющие его циклы.
Оператор continue
Оператор continue. С помощью оператора continue можно организовать преждевременное завершение шага итерации цикла в обход обычной структуры управления циклом.
Оператор continue осуществляет принудительный переход к следующему шагу цикла, пропуская любой код, оставшийся невыполненным. Таким образом, оператор continue служит своего рода дополнением оператора break.
В циклах while и do-while оператор continue вызывает передачу управления непосредственно условному выражению, после чего продолжается процесс выполнения цикла. А в цикле for сначала вычисляется итерационное выражение, затем условное выражение, после чего цикл продолжается.

Результат:
Оператор continue редко находит удачное применение, в частности, потому, что в C# предоставляется богатый набор операторов цикла, удовлетворяющих большую часть прикладных потребностей.
Но в тех особых случаях, когда требуется преждевременное прерывание шага итерации цикла, оператор continue предоставляет структурированный способ осуществления такого прерывания.
Оператор return
Оператор return. Оператор return организует возврат из метода (функции). Его можно также использовать для возврата значения. Имеются две формы оператора return: одна — для методов типа void, то есть тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения.
Для немедленного завершения метода типа void достаточно воспользоваться следующей формой оператора return:
return;
Когда выполняется этот оператор, управление возвращается вызывающей части программы, а оставшийся в методе код пропускается.
Для возврата значения из других (не void) методов в вызывающую часть программы служит следующая форма оператора return:
return значение;
Рассмотрим применение оператора return на конкретном примере:
Результат работы данной программы:

Мы рассмотрели все операторы языка C#. В предпоследней статье этого раздела хотелось бы обратить ваше внимание на использование в языке «знаков препинания«.
NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.
Запретный плод 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:
Очень лаконично и читабельно. Но — нельзя! Попробуем без goto:
Вы что-нибудь поняли из логики работы второго листинга.
Сравним оба листинга:
- На первый листинг я потратил раз в 5 меньше времени, чем на второй.
- Листинг с goto короче как минимум в 2 раза.
- Листинг с goto поймет любой человек с самой минимальной подготовкой в С. Второй же я постарался сделать максимально доступным и очевидным – и все равно, в него надо долго вникать.
- Сколько времени уйдет на отладку первого варианта и сколько на отладку второго?
- И вообще, если считать нарисованный алгоритм постановкой задачи, то первый листинг правильный на 100%. Про второй я до сих пор не очень уверен… хотя бы в очередности проверки условий и флагов.
- Сравните получившийся ассемблерный код первого и второго листинга.
Но зато во втором листинге нет goto!
Ну да ладно, в жизни такие алгоритмы почти не встречаются. Лучше поговорим о жизни.
goto в реальных программах
Я за свой более чем 20-летний стаж прошел несколько аппаратных платформ и с десяток языков программирования, участвовал в написании крупного программного продукта ActiveHDL, делал коммерческую базу данных и много небольших программ для отладки оборудования, используемого в Олимпийских играх, а также делал устройства для этой самой Олимпиады (уже несколько Олимпиад, если быть точным). Короче, что-то я в программировании шарю. А, да, забыл – я закончил с почетным дипломом ХНУРЭ — то бишь, в теории я тоже секу.
Поэтому мои последующие размышления и ситуации… скажем так, я имею моральное право на них.
Неявное использование goto
В языке С есть много операторов, которые на самом деле являются банальным goto – условным или безусловным. Это все виды циклов for (…), while (…) <…>, do <…>while (…). Это анализ числовых переменных switch (…)
С++ добавляет массу невидимых переходов перегрузками, конструкторами и деструкторами. Из явных переходов – try <… throw …>catch (…) <…>.
Эти goto считаются «легальными» — чем же нелегален сам goto?
В чем обвиняют goto
Обвиняют его в том, что код становится нечитабельным, плохо оптимизируемым и могут появиться ошибки. Это про практические минусы. А теоретические – это просто плохо и неграмотно, и все тут!
Насчет нечитабельности кода и плохой оптимизируемости – еще раз взгляните на листинги выше.
Насчет вероятности появления ошибок – согласен, такой код воспринимается несколько сложнее из-за того, что мы привыкли читать листинг сверху вниз. Но и все! А что, другие средства С++ безопасные и не могут создать ошибок в коде? Приведу краткий список самых опасных вещей С++ («опасные» в том смысле, что с их помощью можно создать массу трудноуловимых ошибок): преобразования типов, перегрузка операторов, указатели и динамическое распределение памяти, наследование классов, шаблоны… Кажется, я перечислил почти все достоинства С++… А, ну да, полиморфизм не назвал – он у меня проходит под «перегрузкой операторов».
Вам не кажется, что нож – это очччень опасная вещь? Но почему-то на кухне мы им пользуемся. А 220 вольт – ужас как опасно! Но если пользоваться с умом – жить можно.
Тоже самое и goto. Пользоваться им надо с умом – и тогда код будет работать корректно.
А про теоретические доводы – это, уж простите меня, спор о вкусах. Вы пользуетесь Венгерской нотацией? Я – нет, терпеть ее не могу! Но я ж не говорю, что она плохая из-за этого! Лично я считаю, что переменная должна нести смысловую нагрузку – для чего она создана. Но я не буду запрещать пользоваться этим способом именования другим людям!
Или же есть эстеты, которые считают, что писать a = ++i неграмотно, надо писать i = i + 1; a = i. И что теперь, запретить и это тоже?
Впрочем, есть в C++ ньюанс, где goto приводит к проблемам:
Чему будет равно p? А компилятор его знает! Впрочем, хороший компилятор такого не допустит – или допустит в том случае, если это p нигде не используется.
В то же время выход из цикла вызывает необходимые деструкторы – проверено в Visual Studio 2008.
Что на это скажешь? А то, что не-использование goto не застрахует Вас от неправильно написанной программы. Так же и применение его не гарантирует, что программа будет сыпаться. Нужно писать программы с умом и не делать таких элементарных глюков.
Обработка ошибок
В С++ по сравнению с С появилась замечательная возможность try … throw … catch. Она позволяет эффективно обрабатывать ошибки и прочие сложные ветвления. В С++ — да, но не в С. В С приходится в таком случае использовать goto. Разумеется, можно использовать всяческие флаги и прочее. Но этот вопрос мы уже обсудили – код раздувается, появляются источники новых ошибок, листинг становится нечитабельным.
Это как раз тот самый случай при программировании микроконтроллеров, где я активно использую goto. Это мне позволило не попадать в «зависания» в случае проблем с внешними устройствами, UART, USB и т. п.
Выход из вложенного цикла наружу
Посмотрите на программу ниже:
Что происходит – понятно? Есть вложенный цикл. Если наступило какое-то условие – покидаем все последующие обработки.
Данный код с флагами выглядит иначе:
Что произошло в данном случае? На каждой итерации мы теперь проверяем флаг. Не забываем его проверять и дальше. Это мелочи, если итераций немного и речь идет о «безразмерной» памяти у PC. А когда программа написана для микроконтроллера – это все уже становится существенно.
Кстати, в связи с этим в некоторых языках (если не ошибаюсь, в Java) есть возможность выйти из цикла по метке вида break Leave. Тот же goto, между прочим!
Точно такой же пример я могу привести и с обработкой в switch (…) < case …>. С этим я сталкиваюсь часто при обработке входящих пакетов неодинаковой структуры.
UPD: как мне справедливо подсказали, в данном случае это проблема для С, а не С++. В С++ можно «выскользнуть» наружу с помощью throw… catch…. Но мы помним, что throw… catch… — тот же самый goto!
Автоматическое создание кода
Знакомы ли Вы с автоматным программированием? Или любым другим автоматизированным созданием кода? Скажем, создатели лексических обработчиков (без использования громоздкого boost::spirit). Все эти программы создают код, который можно использовать как «черный ящик» — Вам не важно, что там внутри; Вам важно, что он делает. А внутри там goto используется очень и очень часто…
Кстати, признаком хорошей программы на С++ является создание интерфейсов, которые работают в четко заданных условиях. И Вам знать не надо что там внутри. А, может, там тоже масса goto. Это уже проблема создателя такого класса – придумать, отладить и составить спецификацию. И в рамках этой спецификации заставить его работать стабильно. А внутренности – они не для посторонних.
Выход в одном месте
На С иногда приходится писать что-то вроде:
Этот код гораздо аккуратней будет выглядеть так:
Идея понятна? Иногда надо при выходе что-то сделать. Иногда много чего надо сделать. И тогда тут здорово помогает goto. Такие примеры у меня тоже имеются.
Вроде бы все перечислил, теперь можно подвести…
Это моя точка зрения! И она справедлива для меня. Может – и для Вас, но я не буду Вас заставлять ей следовать!
Так вот, для меня очевидно, что goto помогает оптимальней и качественней решить некоторые проблемы.
А бывает и наоборот – goto может породить массу проблем.
UPD: Начитавшись гору комментариев, я для себя выделил положительные стороны использования goto и отрицательные.