Goto

goto(отангл.go to— «перейти на») — оператор безусловного перехода (перехода к определённой точке программы, обозначенной номером строки либо меткой) в некоторыхязыках программирования. В некоторых языках оператор безусловного перехода может иметь другое имя (например,jmpв языках ассемблера).
Как правило, операторgotoсостоит из двух частей: собственно оператора и метки, указывающей целевую точку перехода в программе:gotoметка. Метка, в зависимости от правил языка, может быть либо числом (как, например, в классическом Бейсике), либо идентификатором используемого языка программирования. Для меток-идентификаторов метка, как правило, ставится перед оператором, на который должен осуществляться переход, и отделяется от него двоеточием (метка:).
Действие оператора перехода состоит в том, что после его исполнения следующими будут исполняться операторы программы, идущие в тексте непосредственно после метки (до следующего оператора перехода, ветвления или цикла). Длямашинных языковинструкция перехода копирует врегистр процессора, содержащий адрес следующей выполняемой команды, адрес команды, помеченной меткой.
Операторgotoимеется в таких языках, какФортран,Алгол,Кобол,Бейсик,СииC++,C#,D,Паскаль,Perl,Ада,PHPи многих других. Он присутствует также во всехязыках ассемблера(обычно под названиемjmp,jumpилиbra(отангл.branch— ветвь)). Свобода использованияgotoв разных языках различается. Если в ассемблерах или языках типа Фортрана он может применяться произвольно (допускается передача управления внутрь ветви условного оператора или внутрь тела цикла или процедуры), то в более высокоуровневых языках его использование ограничено: как правило, с помощьюgotoзапрещено передавать управление между различными процедурами и функциями, внутрь выделенного блока операторов, между ветвями условного оператора и оператора множественного выбора.
gotoотсутствует в некоторых языках высокого уровня (например, вФорт). ВПаскальgotoпервоначально включён не был, но недостаточность имеющихся языковых средств вынудилаНиклауса Виртаего добавить. В более поздних своих языках Вирт всё же отказался отgoto: этого оператора нет ни вМодуле-2, ни вОберонеиКомпонентном Паскале. ВJavaестьзарезервированное словоgoto, но оно не несёт никаких функций — оператора безусловного перехода в языке нет (однако переход осуществить можно). При этом в языке сохранились метки — они могут применяться для выхода из вложенных циклов операторамиbreakиcontinue.
Операторgotoв языках высокого уровня является объектом критики, поскольку чрезмерное его применение приводит к созданию нечитаемого «спагетти-кода». Впервые эта точка зрения была отражена в статьеЭдсгера Дейкстры«Доводы против оператора GOTO»,который заметил, что качество программного кода обратно пропорционально количеству операторовgotoв нём. Статья приобрела широкую известность как среди теоретиков, так и среди практиков программирования, в результате чего взгляды на использование оператораgotoбыли существенно пересмотрены. В своей следующей работе Дейкстра обосновал тот факт, что для кода безgotoнамного легчепроверить формальную корректность.
Код сgotoтрудно форматировать, так как он может нарушать иерархичность выполнения (парадигмуструктурного программирования) и потому отступы, призванные отображать структуру программы, не всегда могут быть выставлены правильно.gotoтакже мешаетоптимизации компиляторамиуправляющих структур.
Некоторые способы примененияgotoмогут создавать проблемы с логикой исполнения программы:
Доводы против оператораgotoоказались столь серьёзны, что вструктурном программированииего стали рассматривать как крайне нежелательный. Это нашло отражение при проектировании новых языков программирования. Например,gotoбыл запрещён вJavaиRuby. В ряде современных языков он всё же оставлен из соображений эффективности в тех редких случаях, когда применениеgotoоправдано. Так,gotoсохранился вАде— одном из наиболее продуманных с точки зрения архитектуры языков за всю историю.Однако в тех современных языках высокого уровня, где этот оператор сохранился, на его использование, как правило, накладываются жёсткие ограничения, препятствующие использованию наиболее опасных методов его применения: например, запрещается передавать управление извне внутрь цикла, процедуры или функции. Стандарт языка C++ запрещает обход инициализации переменной с помощьюgoto.
Формально доказано (теорема Бёма — Якопини), что применениеgotoне является обязательным, то есть не существует такой программы сgoto, которую нельзя было бы переписать без него с полным сохранением функциональности (однако, возможно, с потерей эффективности).
В практическом программировании применениеgotoв некоторых случаях считается допустимым, когда другие средства языка не реализуют или недостаточно эффективно реализуют нужную функциональность.
Главным критерием применимостиgotoявляется ненарушение используемойпарадигмы программирования(в приведённых ниже примерах этоструктурное программирование), в противном случае результат чреват всевозможными побочными эффектами и труднообнаружимыми ошибками.
В некоторых языках нет операторов досрочного завершения цикла или они относятся только к тому извложенных циклов, в котором расположены (например,breakиcontinueв Си). Использованиеgotoдля выхода из нескольких вложенных циклов сразу в этом случае значительно упрощает код программы, избавляя от необходимости применения вспомогательныхпеременных-флагов иусловных операторов.
Другие варианты решения этой проблемы — помещение вложенных циклов в отдельную процедуру и использование оператора выхода из процедуры, а в языках с поддержкойисключений— генерация исключения, обработчик которого располагается за пределами циклов. Однако подобные решения менее эффективны из-за накладных расходов на реализацию, особенно если соответствующий участок кода вызывается многократно.
Пример на языке Си++:
Прямолинейный способ избавления отgoto— создать дополнительную переменную-флаг, сигнализирующую, что надо выйти из внешнего цикла (после выхода из внутреннего поbreak) и обойти блок кода, выполняющийся, когда значение не найдено.
Без изменения структуры кода проблема решается, если командаbreak(или её аналог) позволяет выйти из нескольких вложенных блоков сразу, как вJavaилиАда. Пример на языке Java:
Наиболее элегантный способ выйти из вложенного цикла предлагает язык PHP. После командыbreakможно указать количество циклов, которые нужно покинуть:
Если в языке нет средствобработки исключений, то операторgotoможет использоваться для прерывания «нормального» выполнения кода и перехода к завершающему коду для освобождения занятой памяти и прочих финальных действий. Пример на языке Си:
Безgotoподобный код был бы излишне загромождён множеством дополнительных условных операторовif.
Ещё одним допустимым применением безусловного перехода считается код, который генерируется автоматически, например, генерируемые с помощью программных инструментальных средств лексические и синтаксические анализаторы. Так, код, генерируемый утилитамиyacc,lex,bison, изобилует командамиgoto, но этот код в принципе не предназначен для восприятия и редактирования человеком, а его корректность целиком определяется корректностью создающего его инструмента.
Является необходимым оператором и применяется повсеместно в виде команд условного или безусловного перехода. С годами не наблюдается изменение интенсивности его использования. Более того, большинство вычислительных платформ также поддерживает такое эффективное средство как индексируемый безусловный переход, позволяя за минимальное время (несколько машинных команд, вплоть до одной) передать управление одной из множества подпрограмм, выбор которой определяется содержимым одного из регистров процессора. Однако для этого, нача́ла (точки входа) всех подпрограмм в этом множестве должны быть размещены вОЗУс фиксированным шагом. Так как последнее труднореализуемо средствами языков высокого уровня, в них обычно индексируемый безусловный переход не доступен, его заменяют на менее эффективный табличный поиск.