В информатике, поток управления (или поток управления ) - это порядок, в котором в отдельных инструкции, инструкции или вызовы функций из императивной программы выполнено или оценено. Акцент на явном потоке управления отличает язык императивного программирования от языка декларативного программирования.
В императивном языке программирования оператор потока управления - это оператор, в результате которого делается выбор, по какому из двух или более путей следования. Для нестрогих языковых конструкций существуют функции и языковые конструкции для достижения того же результата, но они обычно не называются операторами потока управления.
Набор операторов, в свою очередь, обычно структурирован как блок , которые включают группирования также определяют лексическую область .
Прерывания и сигналы - это низкоуровневые механизмы, которые могут использовать поток управления способом, подобным подпрограмме, но обычно возникает как реакция на некоторый внешний стимул или событие (может происходить асинхронно ), скорее чем выполнение встроенного оператора потока управления.
На уровне машинного языка или языка ассемблера инструкции потока управления обычно работают путем изменения программного счетчика. Для некоторых центральных процессоров (ЦП) единственными доступными инструкциями потока управления условными или безусловными инструкциями перехода, также называемые переходами.
Типы операторов потока управления, поддерживаемые различные языки различаются, но могут быть разделены на категории по их эффекту:
A метка - это явное имя или номер, присвоенный фиксированной позиции в исходном коде, который может ссылаться поток управления операторы, появляющиеся в другом месте исходного кода. Метка отмечает позицию в исходном коде и не имеет никакого другого эффекта.
Номера строк альтернативной именованной метке, используемой на некоторых языках (например, BASIC ). Это целые числа, помещенные в начало каждой строки текста в исходном коде. Языки в каждой строке, которые они используются, часто накладывают ограничение. Например, в BASIC:
10 LET X = 3 20 PRINT X
На других языках, таких как C и Ada, метка является указателем , обычно появляется в начале строки и сразу после него ставится двоеточие. Например, в C:
Успех: printf («Операция прошла успешно. \ N»);
На языке АЛГОЛ 60 ены как целые числа, так и разрешатели в качестве меток (оба связаны двоеточиями со следующим утверждением), но немногие, если вообще любые другие варианты АЛГОЛ допускают целые число. Ранние компиляторы Fortran допускают только целые числа в качестве меток. Начиная с Fortran-90, также разрешены буквенно-цифровые метки.
Оператор goto (комбинация английских слов go и до и произносится соответствующим образом) является основным формой безусловного передачи управления.
Используемое слово может быть в или нижнем регистре в зависимости от языка, обычно оно записывается как:
goto label
Эффект оператора goto заключается в том, чтобы вызвать выполнение следующего оператора, который должен быть оператором появляющимся на (или сразу после) данным оператором.
операторы Goto считались компьютерщиками, особенно Дейкстра.
Терминология для подпрограмм рассматривается; в качестве альтернативы они могут называться подпрограммами, процедурами, функциями (особенно если они возвращают результаты) или методами (если они принадлежат к классам или классам типов ).
В 1950-х годах память компьютера была очень маленькой по нынешним стандартам, поэтому подпрограммы использовались в основном для уменьшения размера программы. Кусок кода был написан один раз, а затем многократно использовался в различных местах программы.
Сегодня подпрограммы часто используются, чтобы помочь сделать более структурированной структуры, например, путем изоляции некоторого алгоритма или сокрытия некоторого метода доступа к данным. Если над одной программой работают многие программисты, подпрограммы включают один из видов модульности, который может помочь разделить работу.
В структурированном программировании упорядоченная последовательность последовательных команд считается одной из базовых структур управления, которая используется как строительный блок для программ наряду с итерацией, рекурсией и выбором.
В мае 1966 года Бём и Якопини опубликовали статью в «Коммуникациях ACM», в которой было показано, что любую программу с goto можно преобразовать в форма без включения, включающая только выбор (ЕСЛИ ТО ЕЩЕ) и циклы (WHILE условие DO xxx), возможно, с дублированным кодом и / или добавлением логических чисел (флаги true / false). Позднее авторы показывают, что выбор можно заменить циклами (и тем более логическими переменными).
То, что такой минимализм возможен, не означает, что он обязательно желателен; в конце концов, компьютерам теоретически требуется только одна машинная инструкция (вычтите одно число из другого и выполните переход, если результат отрицательный), но на практике компьютеры имеют десятки или даже сотни машинных инструкций.
Статья Бема и Якопини показала, что все программы могут быть без перехода. Другое исследование показывает, что управляющие структуры с одним входом намного легче понять, чем любую другую форму управления. Другими словами, их можно было компоновать. (Более поздние разработки, такие как нестрогуемие языки программирования - в последнее время составные программные транзакции - продолжили эту стратегию, компоненты программ еще более свободно компонентами.)
Некоторые ученые избрали пуристический подход к результату, что даже такие инструкции, как break
и return
из середины цикла, являются плохой практикой, поскольку они не нужны в доказательстве Бема- Якопини, и поэтому они выступали за то, чтобы все петли имели первую точку выхода. Этот пуристический подход воплощен на языке Pascal (использовать в 1968–1969), который до середины 1990-х годов был предпочтительным инструментом для обучения вводному программированию в академических кругах. Прямое применение теоремы Бема-Якопини может привести к введению дополнительных локальных чисел в структурированную диаграмму, а также может привести к некоторому дублированию кода . На Паскаль влияет обе эти проблемы, и согласно эмпирическим исследованиям, процитированным Эриком С. Робертсом, студентам-программистам было трудно определить правильные решения на Паскале для нескольких проблем, включая написание функций для поиска элемента в массив. Исследование 1980 года Генри Шапиро, цитируемое Робертсом, показало, что было дано только 20% испытуемых, в то время как один из испытуемых не написал неправильный код для проблемы, если бы разрешили написать ответ из середина цикла.
Большинство языков программирования с управляющими структурами имеют начальное слово, которое указывает тип задействованной управляющей структуры. Затем языки разделяются относительно того, есть ли у управляющих структур последнее слово.
begin
... end
{
... }
DO
... END
do
... end
end
+ пробел + начальное конкретное слово, например, if
... конец, если
, цикл
... конец цикла
if
... fi
, case
... esac
END
+ начальное специальное слово, например, IF
... ENDIF
, DO
... ENDDO
END
для всегоЕсли
... Конец Если
; Для
... Далее
; Do
... Цикл
; While
... Wend
Условные выражения и условные конструкции являются особенностями язык программирования, который выполняет различные вычисления или действия в зависимости от того, заданное программистом условие логическое оценивается как истинное или ложное.
ЕСЛИ..ПЕРЕЙТИ
. Форма, найденная в неструктурированных языках, имитирующая типичная инструкция машинного кода, перескакивает на (GOTO) метку или номер строки при выполнении условий.ЕСЛИ..ТОГДА.. (ENDIF)
. Вместо того, чтобы ограничиваться переходом, любой простой оператор или вложенный блок может следовать за ключевым словом THEN. Это структурированная форма.ЕСЛИ..ТЕН..ЭЛЬСЕ.. (КОНЕЦ)
. Должно быть выполнено то же, что и выше, но со вторым наступлением, которое должно быть выполнено, если условие ложно. Это одна из самых распространенных форм с множеством вариаций. Некоторым требуется терминал ENDIF
, другим - нет. C и родственные языки не требуют ключевого слова терминала или 'then', но требуют скобок вокруг условий.ELSE
и IF
в ELSEIF
, избегая необходимости иметь серию ENDIF
или других заключительных операторов в конценого оператора.Паскаль : | Ада : | C : | Сценарий оболочки : | Python : | Лисп : |
---|---|---|---|---|---|
если a>0, то Writeln ("да") else Writeln ("нет"); | если a>0, то Put_Line ("да"); иначе Put_Line ("нет"); конец, если; | если (а>0) {printf ("да"); } else {printf ("нет"); } | если [$ a -gt 0]; затем эхо "да" иначе эхо "нет" fi | если a>0: print ("да") else: print ("нет") | (princ (if (plusp a) "да" "нет")) |
Менее распространенные варианты включают:
если
, например cond
.if
, такая как тернарный оператор языка C.if
с , когда
и , if
.ifTrue
и ifFalse
для реализации условных выражений, а не любую фундаментальную языковую конструкцию.Switch операторы (или операторы case, или многосторонние ветви) сравнивают заданное значение с указанными константами и предпринимают действия в соответствии с первой совпадающей константой. Обычно существует положение о том, что действие по умолчанию («иначе», «иначе») должно быть, если совпадение не было успешным. Операторы Switch могут допускать оптимизацию компилятора, например, таблицы поиска. В динамических языков могут не ограничиваться константными выражениями и распространяться на сопоставление с образцом, как в примере сценария оболочки справа, где *)
реализует регистр по умолчанию как glob, соответствующий любой строке. Логика регистратора также может быть реализована в функциональной форме, как в инструкции декодировать
в SQL.
Паскаль : | Ада : | C : | Сценарий оболочки : | Лисп : |
---|---|---|---|---|
case someChar of 'a': actionOnA; 'x': действиеOnX; 'y', 'z': actionOnYandZ; еще действиеOnNoMatch; конец; | case someChar - это когда 'a' =>actionOnA; когда 'x' =>actionOnX; когда 'y' | 'z' =>actionOnYandZ; когда другие =>actionOnNoMatch; конец; | переключатель (someChar) {case 'a': actionOnA; перемена; case 'x': actionOnX; перемена; case 'y': case 'z': actionOnYandZ; перемена; по умолчанию: actionOnNoMatch; } | case $ someChar в a) actionOnA ;; x) actionOnX ;; [yz]) actionOnYandZ ;; *) actionOnNoMatch ;; esac | (case some-char ((# \ a) action-on-a) ((# \ x) action-on-x) ((# \ y # \ z) action-on-y-and- z) (иначе действие при отсутствии совпадения)) |
Цикл - это последовательность операторов, которая задается один раз, но может быть несколько раз подряд. Код "внутри цикла" выполняется какое-либо условие, или бесконечно.
на языках функционального программирования, таких как Haskell и Scheme, циклы могут быть выражены с помощью рекурсии или с фиксированной точкой. итерация, а не явные конструкции цикла. Хвостовая рекурсия - это частный случай рекурсии, который можно легко преобразовать в итерацию.
В большинстве языков программирования есть конструкции для повторения цикла определенное количество раз. В большинстве случаев счет может идти вниз, можно использовать размер шага, отличный от 1.
ДЛЯ I = 1 TO N | для I: = 1 toN doначало xxx | xxx NEXT I | конец ; -------------------------------------------------- ---------- DO I = 1, N | для (I = 1; I <=N; ++I) { xxx | xxx END DO | }
В этих примерах, если N < 1 then the body of loop may execute once (with I having value 1) or not at all, depending on the programming language.
Во многих языках программирования только целые числа люди управляемым цикле, управляемым счетчиком. из-за аппаратных ограничений, поэтому цикл, такой как.
для X: = 0,1, шаг 0,1 до 1,0 do
может повторяться 9 или 10 раз, в зависимости от ошибок округления и / или версии оборудования и / или компилятора. Кроме того, если приращение X происходит путем повторного сложения, накопленные округления означать означать, что значение X на каждой итерации может значительно отличаться от ожидаемой последовательности. 0.1, 0.2, 0.3,..., 1.0.
Большинство языков программирования конструкции конструкции для повторения цикла до тех пор, пока некоторые условия не изменятся. в начале цикла, другие тестируют его в конце.Если тест в начале, может быть пропущено полностью, если оно в конце, тело всегда выполняется хотя бы один раз.
ДЕЛАТЬ ПОКА (тест) | повторить ххх | xxx LOOP | до испытания; ---------------------------------------------- пока (тест) {| делать ххх | xxx} | в то время как (тест);
A Control Break - это метод обнаружения изменений значения, используя в обычных циклах для запуска обработки для групп значений. Значения отслеживаются в цикле, и изменение перенаправляет поток программы на обработку связанного с ними группового события.
DO UNTIL (конец файла) IF new-zipcode <>current-zipcode display_tally (current-zipcode, zipcount) current-zipcode = new-zipcode zipcount = 0 ENDIF zipcount ++ LOOP
Несколько языков программирования (например, Ada, D, C ++ 11, Smalltalk, PHP, Perl, Object Pascal, Java, C#, MATLAB, Visual Basic, Ruby, Python, JavaScript, Fortran 95 и новее) имеют специальные конструкции, которые позволяют неявный цикл по всем элементам массива или всем членам набора или коллекции.
someCollection do : [: eachElement | xxx].
для Элемент в Коллекции doначало xxx конец ; foreach (item; myCollection) {xxx} foreach someArray {xxx} foreach ($ someArray as $ k =>$ v) {xxx} Коллекцияcoll; для (String s: coll) {} foreach (string s inmyStringCollection) {xxx} someCollection | ForEach-Object {$ _}
forall (index = first: last: step...)
Scala имеет for-expression, которые обобщают циклы, управляемые коллекцией, а также поддерживает другие варианты использования, такие как асинхронное программирование. Haskell имеет do-выражения и понимания, которые вместе предоставляют функции, аналогичные функциям for в Scala.
Могут использоваться общие конструкции итерации, такие как для оператора
языка C и do
формы Common Lisp для выражения любого из вышеперечисленных видов циклов и других, таких как параллельный цикл по некоторому количеству коллекций. Там, где может использоваться более конкретная конструкция цикла, она обычно предпочтительнее общей конструкции итерации, поскольку она часто делает цель выражения более ясной.
Бесконечные циклы используются для обеспечения того, чтобы программный сегмент зацикливался вечно или до тех пор, пока не возникнет исключительное условие, такое как ошибка. Например, программа, управляемая событиями (такая как сервер ), должна зацикливаться вечно, обрабатывая события по мере их возникновения,останавливаясь только тогда, когда процесс завершается оператором.
Бесконечные циклы могут быть реализованы с использованием других конструкций потока управления. Чаще всего в неструктурированном программировании это возврат вверх (goto), тогда как в структурированном программировании это неопределенный цикл (цикл while), для которого задано никогда не заканчиваться, либо путем исключения условий, либо путем явной установки его в true, как пока (правда)...
. На некоторых языках есть специальные конструкции для бесконечных циклов, обычно путем исключения условий из неопределенного цикла. Примеры включают Ada (цикл... конец цикла
), Fortran (DO... END DO
), Go (для {...}
), и Ruby (цикл do... end
).
Часто бесконечный цикл непреднамеренно создается из-за ошибки программирования в управляемом условием, при этом условии цикла переменные, которые никогда не изменяются внутри цикла.
Иногда в тележурнале возникает пропустить оставшуюся часть тела и продолжить следующую итерацию цикла. Некоторые языки предоставляют такой оператор, как продолжить
(для многих языков), пропустить
или следующий
(Perl и Ruby), которые будут делать это. Результатом является преждевременное завершение самого внутреннего цикла, а затем возобновление в обычном режиме со следующей итерацией. Результатом будет досрочное завершение всего цикла.
Некоторые языки, такие как Perl и Ruby, имеют оператор redo
, который перезапускает текущую итерацию с самого начала.
Ruby имеет оператор retry
, который перезапускает весь цикл с начальной итерации.
При использовании цикла с управляемым счетчиком для поиска по таблице может быть желательно поиск остановить, как только будет найден требуемый элемент. Некоторые языки программирования программирования такие инструкции, как break
(для многих языков), Exit
(Visual Basic) или last
(Perl), результатом является завершение текущего цикла немедленно и передать управление оператору сразу после этого цикла. Другой термин для циклов раннего выхода - половина цикла.
Следующий пример выполнен в Ада, поддерживает как ранний выход из циклов, так и циклы с тестом в среднем. Сравнение обоих фрагментов кода покажет разницу: ранний выход должен сочетаться с оператором, если, в то время как условие в середине является автономной конструкцией.
с Ada.Text IO; с Ada.Integer Text IO; процедура Print_Squares - X: Integer; begin Read_Data: loop Ada.Integer Text IO.Get (X); выйти из Read_Data, когда X = 0; Ada.Text IO.Put (X * X); Ada.Text IO.New_Line; конец цикла Read_Data; конец Print_Squares;
Python поддерживает условное выполнение кода в зависимости от того, был ли цикл завершен раньше (с помощью оператора break
) или нет с помощью предложения else с циклом. Например,
для n в set_of_numbers: if isprime (n): print («Набор содержит простое число») break else: print («Набор не содержит простых чисел»)
else Предложение
в В приведенном выше примере используется оператором для
, а не с внутренним оператором , если
. Оба цикла Python для
и , в то время как
период такое предложение else, которое выполняется только в том случае, если не произошло раннего выхода из цикла.
Некоторые циклы выход из вложенных; в теоретических кругах это называется многоуровневыми перерывами. Один из распространенных способов использования - поиск в многомерной таблице. Это можно сделать либо с помощью многоуровневых разрывов (из N уровней), как в bash и PHP, либо с помощью помеченных разрывов (разрыв и продолжение с заданной меткой), как в Java и Perl. Альтернативы многоуровневым разрывам включают одиночные разрывы вместе с выходным состоянием, который проверяется для выхода на другой уровень; исключения, которые вылавливаются на разбитом уровне; размещение вложенных циклов в функции и использование возврата для завершения всего вложенного цикла; или используя метку и инструкцию goto. C не включает многоуровневый разрыв, и обычная альтернатива - использовать goto для реализации помеченного разрыва. Python не имеет многоуровневого прерывания или продолжения - это было предложено в PEP 3136 и отклонено на том основании, что дополнительная сложность не стоит редкого законного использования.
Понятие многоуровневого -уровневые разрывы некоторый интерес в теоретической информатике, потому что они порождают то, что сегодня называется иерархией Косараджу. В 1973 С. Рао Косараджу уточнил теорему о структурированной программе, что можно избежать добавления дополнительных чисел в структурированном программировании, если разрешены многоуровневые разрывы произвольной глубины из циклов. Существующая программа строгой иерархии программ: для каждого целого числа существует программа, содержащая многоуровневый разрыв, которую нельзя переписать с многоуровневыми разрывами глубже, меньше без добавления дополнительных переменных.
Можно также вернуть
из подпрограммы, выполняющей зацикленные операторы, выходя как из вложенного цикла, так и из подпрограммы. Существуют и другие предлагаемые управляющие структуры для множественных разрывов, но они обычно реализуются как исключения.
В своем учебнике 2004 года Дэвид Ватт использует понятие секвенсора Теннента, чтобы объяснить сходство между многоуровыми разрывами и операторами возврата. Уотт отмечает, что класс секвенсоров, известные как управляющие секвенсоры, определяемый как «секвенсор, который завершает выполнение команды или процедуры, содержащий текст», включает как разрывы из циклов (включая многоуровневые разрывы), так и операторы возврата. Однако, как обычно реализовано, секвенсоры могут также не возвращать (возвращаемое) значение, тогда как секвенсор прерывания, реализованный на современных языках, обычно не может.
Варианты цикла и инварианты цикла используются для выражения правильности циклов.
На практике цикла - это целочисленное выражение, имеющее начальное неотрицательное значение. Значение должно быть уменьшено во время каждой итерации цикла, но не должно становиться отрицательным при правильном выполнении цикла. Варианты цикла используются, чтобы устойчиво, что цикл завершится.
Инвариант цикла - это утверждение, которое должно быть истинным до первой итерации цикла и оставаться истинным после каждой итерации. Это означает, что при правильном завершении цикла выполняются как условие выхода, так и инвариант цикла. Инварианты цикла используются для определения характеристик цикла во последовательных итераций.
Некоторые языки программирования, такие как Eiffel, содержат встроенные варианты и инвариантов цикла. В других случаях поддержка является надстройкой, например, спецификация языка моделирования Java для Некоторые операторы цикла в Java.
диалекты Лиспа специальный обширный подъязык для описания циклов. Ранний пример можно найти в Конверсионном Лиспе Интерлиспе. Common Lisp предоставляет цикл цикла, который реализует такой подъязык.
Язык программирования | условный | цикл | ранний выход | продолжение цикла | повторить | повторить | средства исправления | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
начало | середина | конец | количество | сбор | общий | бесконечный | вариант | инвариант | |||||
Ada | Да | Да | Да | Да | массивы | Нет | Да | глубоко вложенные | Нет | ||||
APL | Да | Нет | Да | Да | Да | Да | Да | с глубокой вложенностью | Да | Нет | Нет | ||
C | Да | Нет | Да | Нет | Нет | Да | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
C ++ | Да | Нет | Да | Нет | Да | Да | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
C# | Да | Нет | Да | Нет | Да | Да | Нет | глубоко вложенный | глубоко вложенный | ||||
COBOL | Да | Нет | Да | Да | Нет | Да | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
Common Lisp | Да | Да | Да | Да | только встроенный | Да | Да | глубоко вложенный | Нет | ||||
D | Да | Нет | Да | Да | Да | Да | Да | глубоко вложенный | глубоко вложенный | Нет | |||
Eiffel | Да | Нет | Нет | Да | Да | Да | Нет | один уровень | Нет | Нет | Нет | только целое число | Да |
F# | Да | Нет | Нет | Да | Да | Нет | Нет | Нет | Нет | Нет | |||
FORTRAN 77 | Да | Нет | Нет | Да | Нет | Нет | Нет | один уровень | Да | ||||
Fortran 90 | Да | Нет | Нет | Да | Нет | Нет | Да | глубоко вложенный | Да | ||||
Fortran 95 и более поздние версии | Да | Нет | Нет | Да | массивы | Нет | Да | глубоко вложенные | Да | ||||
Haskell | Нет | Нет | Нет | Нет | Да | Нет | Да | Нет | Нет | Нет | |||
Java | Да | Нет | Да | Нет | Да | Да | Нет | Нет вложенный | глубоко вложенный | Нет | неродной | неродной | |
JavaScript | Да | Нет | Да | Нет | Да | Да | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
Естественный | Да | Да | Да | Да | Нет | Да | Да | Да | Да | Да | Нет | ||
OCaml | Да | Нет | Нет | Да | массивы, списки | Нет | Нет | Нет | Нет | Нет | |||
PHP | Да | Нет | Да | Нет | Да | Да | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
Perl | Да | Нет | Да | Нет | Да | Да | Нет | глубоко вложенный | глубоко вложенный | Да | |||
Python | Да | Нет | Нет | Нет | Да | Нет | Нет | глубоко вложенный | глубоко вложенный | Нет | |||
REBOL | Нет | Да | Да | Да | Да | Нет | Да | один уровень | Нет | Нет | |||
Руби | Да | Нет | Да | Да | Да | Нет | Да | глубоко вложенный | глубоко вложенный | Да | Да | ||
Standard ML | Да | Нет | Нет | Нет | массивы, списки | Нет | Нет | Нет | Нет | Нет | |||
Visual Basic.NET | Да | Нет | Да | Да | Да | Нет | Да | один уровень на типе петли | один уровень на типе петли | ||||
PowerShell | Да | Нет | Да | Нет | Да | Да | Нет | ? | Да |
while (true)
не считается бесконечным циклом для этой цели, потому что это не специальная языковая структура.for (init; контрольная работа; инкремент)
цикл - это общая конструкция цикла, а не подсчет, хотя он часто используется для этого.range ()
.while
.std::for_each
template, которая может выполнять итерацию по контейнерам STL и вызывать унарный функция для каждого элемента. Функциональные возможности также могут быть сконструированы как макрос для этих контейнеров.retry
, однако оно используется в обработке исключений, а не в управлении циклом.GO TO
и процедур.Многие языки программирования, особенно те, которые предпочитают более динамические стили программирования, предлагают конструкции для нелокального потока управления. Это заставляет поток выполнения выскакивать из заданного контекста и возобновляться в какой-то заранее заявленный момент. Условия, исключения и продолжения - это три распространенных типа нелокальных управляющих конструкций; существуют и более экзотические, такие как генераторы, сопрограммы и ключевое слово async.
PL / I имеет около 22 стандартных условий (например, ZERODIVIDE SUBSCRIPTRANGE ENDFILE), которые могут быть вызваны и которые могут быть перехвачены: могут быть условия ON; Программисты также могут определять и использовать свои собственные именованные условия.
Подобно неструктурированному, если может быть указан только один оператор, поэтому во многих случаях требуется GOTO, чтобы решить, где возобновить поток управления.
К сожалению, некоторые реализации использовали значительные накладные расходы как в пространство, так и во времени (особенно SUBSCRIPTRANGE).
Общие примеры синтаксиса:
ONусловие GOTO метка
На современных языках есть специализированная структурированная конструкция для обработки исключений, которая не зависит от использование GOTO
или (многоурового) прерывает или возвращает. Например, в C ++ можно написать:
try {xxx1 // Где-то здесь xxx2 // use: '' 'throw' '' someValue; xxx3} catch (someClass someId) {// поймать значение someClass actionForSomeClass} catch (someType anotherId) {// поймать значение someType actionForSomeType} catch (...) {// поймать то, что еще не было поймано actionForAnythingElse}
Любое количество и разнообразие предложений catch
можно использовать выше. Если нет catch
, соответствующему конкретному throw
, управление просачивается обратно через вызовы подпрограмм и / или вложенные блоки до тех пор, пока не будет найден соответствующий catch
или до конца сообщением об ошибке.
Благодаря влиянию C ++, catch
- ключевое слово, зарезервированное для объявления обработчика исключений сопоставления с образцом в других популярных сегодня языках, таких как Java или C #. Некоторые другие языки, такие как Ada, используют ключевое слово исключение
для введения обработчика исключений, а могут даже использовать другое слово (при
в Ada) для сопоставления с образцом. Некоторые языки, такие как AppleScript, включают заполнители в синтаксис обработчика исключений для автоматического извлечения фрагментов информации при возникновении исключения. Пример подхода такой конструкции конструкции при ошибке
из AppleScript:
пример установить для myNumber значение myNumber / 0 при ошибке e число от f до t частичный результат pr if (e = «Невозможно разделить на ноль»), затем отобразите диалоговое окно «Вы не должны этого делать» end try
В учебнике Дэвида Ватта 2004 г. также анализируется обработка исключений в этой статье в разделе о раннем выходе из циклов. Ватт отмечает, что ненормальная ситуация, обычно представленная арифметическим переполнением или ошибками ввода / вывода вывода, например, файл не найден, является своего рода ошибкой, которая «создается в некотором программном модуле низкого уровня, но [для которой] »Например, программа может содержать несколько программ для чтения файлов, но действие, которое выполняется выполнить, когда файл не найден, зависит от этой (цели), о котором идет речь в программе, и, следовательно, процедура обработки ненормальной ситуации не может находиться в системном коде нижнего уровня. Уоттс далее отмечает, что введение тестирования флагов состояния в вызывающей программе, как это повлечет за структурированное программирование с одним выходом или секвенсоры возврата (с выполнением выходами), приводит к ситуации, когда «приложение имеет тенденцию быть загроможденным тестированием флагов состоян ия» и что «программист может по забывчивости или лениво пропустить проверку флага состояния. Фактически, ненормальные ситуации, представленные флагами состояния, по умолчанию игнорируются! »Ватт отмечает, что в отличие от тестирования флагов состояния, исключают противоположное поведение по умолчанию , вызывая завершение программы, если программист явно не обработан исключение каким-либо образом, возможно, добавлен явный код для его игнорирования. Основываясь на этих аргументах, ватт приходит к выводу, что секвенсоры перехода или управляющие не подходят, как выделенный секвенсор исключений с семантикой, рассмотренной выше.
В Object Pascal, D, Java, C # и Python a наконец, предложение
можно добавить в конструкцию публикации
. Независимо от того, как контроль оставляет iPad
, код внутри предложения наконец
гарантированно выполнится. Это полезно при написании кода, который должен освободить дорогостоящий ресурс (например, открытый файл или соединение с базой данных) после завершения обработки:
FileStream stm = null; // Пример C # try {stm = new FileStream ("logfile.txt", FileMode.Create); вернуть ProcessStuff (stm); // может вызвать исключение} finally {if (stm! = null) stm.Close (); }
Мне этот шаблон распространен, C # имеет особый синтаксис:
using (var stm = new FileStream ("logfile.txt", FileMode.Create)) {return ProcessStuff (stm); // может вызвать исключение}
После выхода из с помощью
-блока компилятор, что объект stm
освобожден, эффективно привязывая переменную к файловый поток, абстрагируясь от побочных эффектов инициализации и освобождения файла. Python с оператором
и аргумент блока Ruby для File.open
используются с аналогичным эффектом.
Все указанные выше параметры определяют стандартные исключения и обстоятельства, при которых они возникают. Пользователи могут создать собственные исключения; на самом деле C ++ позволяет вводить и ловить практически любой тип, включая базовые типы, такие как int
, тогда как другие языки, такие как Java, не столь разрешительны.
В C # 5.0 появилось слово async для поддержки асинхронного ввода-вывода в «прямом стиле».
Генераторы, также известные как полупрограммы, используемое временное управление методуителя, обычно используя слово yield
(yield description ). Подобно ключевому слову async, он поддерживает программирование в «прямом стиле».
Сопрограммы - это функции, которые могут передать управление друг другу - совместная многозадачности без потоков.
Сопрограммы могут быть реализованы как библиотека, если язык программирования либо продолжения, либо генераторы, различные программы между сопрограммами и генераторами на практике технических деталью.
Язык программирования | условия | исключение | генераторы / сопрограммы | async |
---|---|---|---|---|
Ada | Нет | Да | ? | ? |
C | Нет | Нет | Нет | Нет |
C ++ | Нет | Да | да, с помощью BOOST | ? |
C# | Нет | Да | Да | Да |
COBOL | Да | Да | Нет | Нет |
Common Lisp | Да | Нет | ? | ? |
D | Нет | Да | Да | ? |
Эйфель | Нет | Да | ? | ? |
Эрланг | Нет | Да | Да | ? |
F# | Нет | Да | Да | Да |
Go | Нет | Да | Да | ? |
Haskell | Нет | Да | Да | Нет |
Java | Нет | Да | Нет | Нет |
JavaScript | ? | Да | Да, ES6 | Да, этап 3 |
Objective-C | Нет | Да | Нет | ? |
PHP | Нет | Да | Да | ? |
PL / I | Да | Нет | Нет | Нет |
Python | Нет | Да | Да | Да |
REBOL | Да | Да | Нет | ? |
Руби | Нет | Да | Да | ? |
Ржавчина | Нет | Да | экспериментальный | Да |
Scala | Нет | Да | через экспериментальное расширение | через экспериментальное расширение |
Tcl | через трассировки | Да | Да | через цикл событий |
Visual Basic.NET | Да | Да | Нет | ? |
PowerShell | Нет | Да | Нет | ? |
Подделкой В статье Данные 1973 года Р. Лоуренс Кларк оператором используя оператор GOTO COMEFROM и привел несколько интересных примеров. COMEFROM был реализован на одном эзотерическом языке программирования, названном INTERCAL.
в статье Дональда Кнута 1974 года «Структурированное программирование с использованием агента», в котором определены две ситуации, которые не были охвачены системой управления. структур, перечисленных выше, и привели примеры структур управления, которые могут справиться с этой ситуацией. Несмотря на их полезность, эти конструкции еще не нашли своего применения в основных языках программирования.
Следующее было предложено Далем в 1972 году:
цикл цикл xxx1 чтение (char) ; в то время как тест; в то время как не atEndOfFile; xxx2 запись (символ); повторить ; repeat ;
Если xxx1 опущено, мы получаем цикл с тестом наверху (цикл while ). Если xxx2 опущено, мы получаем цикл с тестом внизу, эквивалентный циклу do while на многих языках. Если в то время как опущено, мы получим бесконечный цикл. Конструкцию здесь можно представить как цикл сделать с проверкой пока в середине. Следовательно, эта единственная конструкция может заменить несколько конструкций в большинстве языков программирования.
Языки, в которых отсутствует эта конструкция, обычно эмулируют ее, используя эквивалентную идиому бесконечного цикла с прерыванием:
, в то время как (верно) {xxx1 if(не тест) break xxx2}
Возможный вариант - разрешить более одного при тесте; использование внутри цикла, но exitwhen (см. следующий раздел), кажется, лучше охватывает этот случай.
В Ada указанная выше конструкция цикла (цикл - в то время как - повторение ) может быть представлен С использованием стандартного бесконечного цикла (цикл - конец цикла ), имеющий в середине предложение выход, когда (не путать с оператором выход, когда в в следующем разделе).
с Ada.Text_IO; с Ada.Integer_Text_IO; процедура Print_Squares - X: Integer; начало Read_Data: цикл Ada.Integer_Text_IO.Get (X); выйти из Read_Data, когда X = 0; Ada.Text IO.Put (X * X); Ada.Text IO.New_Line; конец цикла Read_Data; конец Print_Squares;
Именование цикла (например, Read_Data в этом примере) необязательно, но позволяет выйти из внешнего цикла нескольких вложенных циклов.
Это было предложено Зан в 1974 году. Здесь представлена модифицированная версия.
exitwhen EventA или EventB или EventC; xxx exits EventA: actionA EventB: actionB EventC: actionC endexit ;
exitКогда используется для указаний событий, которые могут произойти в пределах xxx, их появление указано с помощью имени события как заявление. Когда какое-либо событие все же происходит, выполняется соответствующее действие, а затем управление переходит сразу после endexit . Эта конструкция обеспечивает очень четкое разделение между определением того, что определенная ситуация применима, и действия, которые необходимо предпринять в этой ситуации.
exitwhen концептуально аналогичен обработка исключений, и исключения или аналогичные конструкции используются для этой цели во многих языках.
Следующий простой пример включает поиск определенного элемента в двумерной таблице.
выйти, если найдено, или отсутствует; для I: = 1 toN doдля J: = 1 toM doifтаблица [I, J] = цель, затем найдено; отсутствует; выходит из найдено: print («элемент находится в таблице»); отсутствует: print («товар отсутствует в таблице»); endexit ;
Один из способов атаки на часть программного обеспечения - перенаправить поток выполнения программы. Разнообразные методы целостности потока управления, включая канарейки стека, защиту от переполнения буфера, теневые стеки и проверка указателя vtable, используются для защиты от этих атак.
![]() | В Wikibook Программирование на Ada есть страница по теме: Control |
![]() | Wikibook Компьютерное программирование имеет страницу на тему: Управление |