Книга: Goto «Labor in International Trade Theory»

Labor in International Trade Theory

Производитель: "Неизвестный"

Labor in International Trade Theory ISBN:9780801840050

Издательство: "Неизвестный" (1990)

ISBN: 9780801840050

GOTO

GOTO (англ. go to — «перейти к») — в некоторых языках программирования — оператор безусловного перехода (перехода к определённой точке программы, обозначенной номером строки либо меткой). В более широком смысле, под «GOTO» подразумевают любой такой оператор, даже если в рассматриваемом языке он называется по-другому. В компилируемых языках GOTO можно рассматривать как основную операцию по передаче управления из одной части программы в другую, поскольку компилятор переводит все остальные операторы перехода в форму, аналогичную GOTO.

Содержание

Функциональность

В абсолютном большинстве языков программирования, поддерживающих его использование, оператор GOTO состоит из двух частей: собственно имени оператора и метки, маркирующей целевую точку перехода в программе, то есть имеет вид GOTO метка. Метка, в зависимости от правил языка, может быть либо числом (как, например, в классическом Бейсике), либо правильным идентификатором используемого языка программирования. Чтобы оператор перехода был корректным, необходимо наличие в тексте программы места, помеченного той же самой меткой, которая использована в данном операторе. Пометка может выглядеть по-разному, например, в языке Паскаль она имеет вид метка: (то есть имя метки, за которым следует двоеточие), возможны и другие соглашения.

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

Распространение

GOTO имеется в таких языках, как Фортран, Алгол, КОБОЛ, Бейсик, Си, C++, C#, D, Паскаль, Perl, Ада, PHP, а также во многих других. GOTO присутствует также во всех языках ассемблера в форме JMP, JUMP или BRA (от англ. branch — ветвь) и используется там чрезвычайно активно. Свобода использования оператора GOTO в различных языках сильно различается. Если в ассемблерах или языках типа Фортрана он может применяться произвольно (допускается передача управления внутрь ветви условного оператора или внутрь тела цикла, а иногда и процедуры), то в более поздних языках высокого уровня его использование ограничено: как правило, с помощью GOTO запрещено передавать управление между различными процедурами и функциями, внутрь выделенного блока операторов, между ветвями условного оператора и оператора множественного выбора.

GOTO отсутствует в некоторых языках высокого уровня, например в Forth (но может быть реализовано средствами самого языка). В Паскаль GOTO первоначально включён не был, но недостаточность имеющихся языковых средств вынудила Никлауса Вирта его добавить. В более поздних своих языках Вирт всё же отказался от GOTO: этого оператора нет ни в Модуле-2, ни в Обероне и Компонентном Паскале. В Java есть зарезервированное слово goto, но оно не несёт никаких функций — оператора безусловного перехода в языке нет. Однако переход осуществить можно. При этом в языке сохранились метки — они могут применяться для выхода из вложенных циклов операторами break и continue.

Критика

Оператор GOTO в языках высокого уровня является объектом критики, поскольку чрезмерное его применение приводит к созданию нечитаемого «спагетти-кода». Впервые эта точка зрения была отражена в статье Эдсгера Дейкстры «Доводы против оператора GOTO»[1], который заметил, что качество программного кода обратно пропорционально количеству операторов GOTO в нём. Статья приобрела широкую известность как среди теоретиков, так и среди практиков программирования, в результате чего взгляды на использование оператора GOTO были существенно пересмотрены. В своей следующей работе Дейкстра обосновал тот факт, что для кода без GOTO намного легче проверить формальную корректность.

Код с GOTO трудно форматировать, так как он может нарушать иерархичность выполнения (то есть парадигму структурного программирования), и потому отступы, призванные отображать структуру программы, не всегда могут быть выставлены правильно. GOTO также аннулирует многие возможности компилятора по оптимизации управляющих структур[2].

Некоторые способы применения GOTO могут создавать проблемы с логикой исполнения программы. Так, например:

  • В языках, имеющих блочную структуру, допускающую описание в каждом блоке своих локальных переменных (например, в C или C++), передача управления внутрь блока «обходит» часть описаний этих переменных. Соответственно, может быть пропущено выделение памяти и вызов конструкторов для некоторых локальных переменных. По завершении блока будет происходить (в случае C++) вызов деструкторов для всех объявленных в блоке переменных, после чего — автоматическое удаление локальных переменных из памяти. В результате, как минимум, будут вызваны деструкторы для переменных, для которых не вызывались конструкторы, а в худшем случае произойдёт попытка освобождения не выделенной памяти, что вызовет ошибку.
  if (a > 0) {goto inner};
  ... // какие-то команды
  {
    X ax = X(a);
    ... // какие-то команды
  inner:
    // Сюда произойдёт переход по goto
    ...
    // По завершении всех команд блока компилятор вызовет 
    // деструктор ~X() для переменной ax.
  }
В вышеприведённом примере в случае перехода по goto в конце блока, выделенного фигурными скобками, будет вызван деструктор для ax, хотя конструктор для этой переменной не вызывался.
  • Передача управления внутрь тела цикла приводит к пропуску кода инициализации цикла или первоначальной проверки условия. Последствия непредсказуемы.
  • Передача управления между ветвями условного оператора приводит к тому, что выполняется часть команд, соответствующих выполнению условия, и часть команд, соответствующих его ложности.
  • Передача управления внутрь процедуры или функции может приводить к непредсказуемым последствиям. Поскольку правильная команда вызова процедуры не выполнялась, на вершине стека возврата находится адрес возврата из той процедуры, откуда вызвался GOTO, за которым, возможно, находится содержимое локальных переменных процедуры, если они размещаются в стеке. В результате, если только такая ситуация не обрабатывается компилятором специально, по завершении процедуры или функции, внутрь которой произведён переход, произойдёт разрушение стека и переход по непредсказуемому адресу.

Доводы против оператора GOTO оказались столь серьёзны, что в структурном программировании его стали рассматривать как крайне нежелательный. Это нашло своё отражение при проектировании новых языков программирования. Например, GOTO был намеренно полностью запрещён в Java и Ruby. Вместе с тем, в ряде современных языков он оставлен из соображений эффективности кодирования в тех редких случаях, когда применение GOTO оправданно. Так, GOTO сохранился в Аде — одном из наиболее продуманных с точки зрения архитектуры языке за всю историю[3]. Однако в тех современных языках высокого уровня, где этот оператор существует, на его использование, как правило, накладываются жёсткие ограничения, препятствующие использованию наиболее опасных методов его применения. В частности, как правило, категорически запрещается передавать управление извне процедуры или функции внутрь неё, извне цикла — внутрь его тела, из одной ветви условного оператора или оператора-переключателя — в другую его ветвь. ANSI-стандарт языка C++ запрещает обход инициализации переменной с помощью GOTO (то есть фрагмент кода, приведённый выше, современным транслятором, например, gcc 4.5, будет отвергнут как синтаксически некорректный). Встречаются и более жёсткие ограничения, например, запрет на передачу управления по GOTO внутрь любого выделенного блока в программе извне этого блока.

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

Оправданное применение

Тем не менее, в практическом программировании применение GOTO в некоторых случаях можно считать допустимым. Поскольку GOTO — «простейший», «атомарный» оператор перехода, а все остальные являются «составными», производными от него, то применение GOTO допустимо и оправданно, когда другие средства языка не реализуют или недостаточно эффективно реализуют нужную функциональность. К таким случаям можно отнести:

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

Обычно считается, что в языках, где операторы досрочного завершения цикла (такие, как break и continue в Си) могут относиться только к тому из вложенных циклов, в котором они расположены, использование goto допустимо, чтобы выйти из нескольких вложенных циклов сразу. Здесь GOTO значительно упрощает программу, избавляя от необходимости создания вспомогательных переменных-флагов и условных операторов.

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

Пример:

int matrix[n][m];
int value;
...
for(int i=0; i<n; i++)
  for (int j=0; j<m; j++)
    if (matrix[i][j] == value)
    {
      printf("value %d found in cell (%d,%d)\n",value,i,j);
      //act if found
      goto end_loop;
    }
printf("value %d not found\n",value);
//act if not found
end_loop: ;

Прямолинейный способ избавления от GOTO — создать дополнительную переменную-флаг, сигнализирующую, что надо выйти из внешнего цикла (после выхода из внутреннего по break) и обойти блок кода, выполняющийся, когда значение не найдено. Но вряд ли этот способ можно рекомендовать на практике, так как в результате код окажется загромождён проверками, станет длиннее и будет дольше работать. Но можно вынести код в функцию и использовать return.

Без изменения структуры кода проблема решается, если команда break (или её аналог) позволяет выйти из нескольких вложенных блоков сразу, как в Java или Ada. Аналогичный код на Java никакого goto не требует:

int[][] matrix;
int value;
...
outer: {
  for(int i=0; i<n; i++)
    for (int j=0; j<m; j++)
      if (matrix[i][j] == value)
      {
        System.out.println("value " + value + " found in cell (" + i + "," + j + ")");
        break outer;
      }
  System.out.println("value " + value + " not found");
}

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

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

Этот случай применим к языкам, не содержащим конструкции try ... finally — например, к C без применения SEH, существующего только в Windows. В этом случае goto используется для перехода на код «очистки» — находящийся в конце функции и уничтожающий созданные ею объекты перед выходом из неё. Этот метод широко используется при написании драйверов.

Пример такой обработки ошибок (все имена и константы, кроме NULL, вымышлены и приведены лишь для примера):

int fn( int* presult )
{
  int sts = 0;
  TYPE entity, another_entity = NULL;
  TYPE2 entity2 = NULL;
 
  if ( !( entity = create_entity() ) )
    { sts = ERROR_CODE1; goto exit0; }
 
  if ( !do_something( entity ) )
    { sts = ERROR_CODE2; goto exit1; }
 
  if ( condition ) {
    if ( !( entity2 = create_another_entity() ) )
      { sts = ERROR_CODE3; goto exit1; }
 
    if ( ( *presult = do_another_thing( entity2 ) == NEGATIVE )
      { sts = ERROR_CODE4; goto exit2; }
  } 
  else {
    if ( ( *presult = do_something_special( entity ) == NEGATIVE )
      { sts = ERROR_CODE5; goto exit2; }
  }
  exit2: if ( entity2 ) destroy_another_entity( entity2 );
  exit1: destroy_entity( entity );
  exit0: return sts;
}

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

Главным критерием применимости goto во всех случаях, включая указанные, является ненарушение используемой парадигмы программирования. В приведенных примерах это — структурное программирование, то есть должны сохраняться иерархическая организация программы и таковая же логика её работы. Нарушение принципа иерархии (например: переходы внутрь цикла; обход операций инициализации — как явных, так и неявных; выход из кода, следующего за fork(), в код, предшествующий ему) чревато всевозможными побочными эффектами, возникающими из деталей трансляции программы в машинный код, и, как следствие, странными, труднообнаружимыми ошибками.

Автогенерация кода

Ещё одним допустимым применением безусловного перехода является код, который генерируется автоматически, например, генерируемые с помощью программных инструментальных средств лексические и синтаксические анализаторы. Например, код, генерируемый утилитами yacc, lex, bison изобилует командами goto, но в этом нет ничего плохого, так как этот код в принципе не предназначен для восприятия и редактирования человеком, а его корректность целиком определяется корректностью создающего его инструмента. Иначе говоря, здесь имеет место та же самая ситуация, что в случае с компилятором языка высокого уровня, создающим машинный код (с неизбежными командами безусловного перехода) просто потому, что таков целевой язык.

См. также

  • Теорема Бома — Якопини

Примечания

Ссылки

Источник: GOTO

Другие книги схожей тематики:

АвторКнигаОписаниеГодЦенаТип книги
Pamela Smith J.Global Trade Policy. Questions and AnswersUsing a unique, question-based format, Global Trade Policy offers accessible coverage of the key questions in trade and policy; it charts the changing policy landscape and evolving institutional… — John Wiley&Sons Limited, электронная книга Подробнее...
7804.74электронная книга
Ashenfelter O.Handbook of Labor Economics Volume 3 Set: (A-C) (количество томов: 3)Handbook of Labor Economics is presented in 3 volume set. Preliminary. Perspectives on the past and prospects for the future: An American perspective. Perspectives on the past and prospects for the… — Elsevier, Handbook of Labor Economics Подробнее...1999
40061бумажная книга
John Black, Nigar Hashimzade, Gareth MylesDictionary of EconomicsThis authoritative and comprehensive dictionary contains clear, concise definitions of over 3400 key economic terms, covering all aspects of the field, including economic theory, applied… — Oxford University Press, (формат: 130x195, 480 стр.) Подробнее...2013
1329бумажная книга

См. также в других словарях:

  • International trade — is exchange of capital, goods, and services across international borders or territories. [ [http://dictionary.reference.com/browse/trade dictionary.reference.com] ] In most countries, it represents a significant share of gross domestic product… …   Wikipedia

  • New Trade Theory — Economics …   Wikipedia

  • Labor history of the United States — involves the history of organized labor, as well as the more general history of working people in the United States of America. Pressures dictating the nature and power of organized labor have included the evolution and power of the corporation,… …   Wikipedia

  • Trade union — Unions redirects here. For the defunct Australian rules football club, see Unions Football Club. Labour union redirects here. For the Polish political party, see Labour Union (Poland). For the Canadian political party, see Union Labour. Labor… …   Wikipedia

  • Labor theory of value — The labor theories of value (LTV) are theories in economics according to which the values of commodities are related to the labor needed to produce them.There are many different accounts of labor value, with the common element that the value of… …   Wikipedia

  • Labor rights — Part of a series on Organized labour …   Wikipedia

Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»