stringtranslate.com

Оператор возврата

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

Обзор

В C и C++ ( где выражение ) — это оператор , который сообщает функции о необходимости вернуть выполнение программы вызывающей функции и сообщить значение . Если функция имеет тип возврата void , оператор return может использоваться без значения, и в этом случае программа просто выходит из текущей функции и возвращается к вызывающей. [1] [2] Подобный синтаксис используется в других языках, включая Modula-2 [3] и Python . [4]return exp;expexp

В Паскале нет оператора возврата. Функции или процедуры автоматически возвращаются при достижении своего последнего оператора. Возвращаемое значение функции предоставляется внутри функции путем присвоения идентификатора с тем же именем, что и у функции. [5] Однако некоторые версии Паскаля предоставляют специальную функцию , которую можно использовать для немедленного возврата значения из функции или, без параметров, для немедленного возврата из процедуры. [6]Exit(exp);

Как и Pascal, FORTRAN II , Fortran 66 , Fortran 77 и более поздние версии Fortran указывают возвращаемые значения путем присвоения имени функции, но также имеют оператор return; этот оператор не указывает возвращаемое значение и для функции вызывает возврат значения, присвоенного имени функции. [5] [7] [8]

В некоторых других языках вместо идентификатора функции используется определяемый пользователем выходной параметр . [9]

Оберон ( Оберон-07 ) имеет предложение возврата вместо оператора возврата. Предложение return помещается после последнего оператора тела процедуры. [10]

Некоторые языки программирования, ориентированные на выражения , такие как Lisp , Perl и Ruby , позволяют программисту опускать явный оператор возврата, указывая вместо этого, что последнее вычисленное выражение является возвращаемым значением подпрограммы. В других случаях возвращается значение Null, если нет явного оператора return: в Python значение Noneвозвращается, когда оператор return опущен, [4] тогда как в JavaScript значение undefinedвозвращается.

В Windows PowerShell все вычисленные выражения, которые не были захвачены (например, присвоены переменной, приведены к void или переданы по конвейеру в $null ), возвращаются из подпрограммы как элементы массива или как один объект в случае, если только один объект не был захвачен.

В Perl возвращаемое значение или значения подпрограммы могут зависеть от контекста, в котором она была вызвана. Самым фундаментальным различием является скалярный контекст, в котором вызывающий код ожидает одно значение, контекст списка , в котором вызывающий код ожидает список значений, и пустой контекст, в котором вызывающий код вообще не ожидает никакого возвращаемого значения. Подпрограмма может проверять контекст с помощью wantarrayфункции. Специальный синтаксис возврата без аргументов используется для возврата неопределенного значения в скалярном контексте и пустого списка в списковом контексте. Скалярный контекст можно дополнительно разделить на логический , числовой, строковый и различные контексты ссылочных типов. Кроме того, контекстно-зависимый объект может быть возвращен с использованием контекстной возвращаемой последовательности с ленивой оценкой скалярных значений.

Многие операционные системы позволяют программе возвращать результат (отдельный от обычного вывода ) при завершении ее процесса; эти значения относятся к статусам выхода . Объем информации, которая может быть передана таким образом, весьма ограничен и на практике часто ограничивается сигнализацией об успехе или неудаче. Изнутри программы этот возврат обычно достигается путем вызова Exit (системного вызова) (распространенного даже в C, где доступен альтернативный механизм возврата из основной функции ).

Синтаксис

Операторы возврата бывают разных форм. Наиболее распространены следующие синтаксисы:

В некоторых языках ассемблера , например, в MOS Technology 6502 , используется мнемоника «RTS» (ReTurn from Subroutine).

Несколько операторов возврата

Языки с явным оператором возврата создают возможность использования нескольких операторов возврата в одной и той же функции. Хорошо это или нет, вопрос спорный.

Убежденные приверженцы структурного программирования следят за тем, чтобы каждая функция имела один вход и один выход (SESE). Таким образом, утверждалось [14] , что следует избегать использования явного оператора возврата, за исключением текстового конца подпрограммы, учитывая, что, когда он используется для «раннего возврата», он может страдать от тех же проблем. которые возникают для оператора GOTO . И наоборот, можно утверждать, что использование оператора return имеет смысл, когда альтернативой является более запутанный код, например, более глубокая вложенность, ухудшающая читаемость.

В своем учебнике 2004 года Дэвид Уотт пишет, что «часто желательны потоки управления с одним входом и множеством выходов». Используя понятие секвенсора Теннента , Ватт единообразно описывает конструкции потока управления, встречающиеся в современных языках программирования, и пытается объяснить, почему определенные типы секвенсоров предпочтительнее других в контексте потоков управления с несколькими выходами. Ватт пишет, что неограниченные переходы (секвенсоры переходов) плохи, потому что пункт назначения перехода не является самоочевидным для читателя программы до тех пор, пока читатель не найдет и не исследует фактическую метку или адрес, который является целью перехода. Напротив, Уотт утверждает, что концептуальная цель возвращаемого секвенсора ясна из его собственного контекста, без необходимости изучения его назначения. Более того, Ватт пишет, что класс секвенсоров, известный как escape-секвенсоры , определяемый как «секвенсор, который завершает выполнение текстовой команды или процедуры», включает в себя как выходы из циклов (включая многоуровневые разрывы), так и операторы возврата. Уотт также отмечает, что, хотя секвенсоры переходов (гото) были несколько ограничены в таких языках, как C, где целью должен быть внутренний локальный блок или охватывающий внешний блок, одного этого ограничения недостаточно, чтобы сделать назначение переходов в C самостоятельным. -описывая, и поэтому они все еще могут создавать « спагетти-код ». Ватт также исследует, чем секвенсоры исключений отличаются от секвенсоров escape и jump; подробнее об этом см. статью о структурном программировании. [15]

Согласно эмпирическим исследованиям, на которые ссылается Эрик С. Робертс , студентам-программистам было трудно сформулировать правильные решения для нескольких простых задач на таком языке, как Паскаль, который не допускает множественных точек выхода. Что касается проблемы написания функции для линейного поиска элемента в массиве, исследование Генри Шапиро 1980 года (цитируемое Робертсом) показало, что при использовании только структур управления, предоставленных Паскалем, правильное решение дали только 20% испытуемых. , хотя ни один субъект не написал неправильный код для этой проблемы, если разрешено писать возврат из середины цикла. [16]

Другие, в том числе Кент Бек и Мартин Фаулер, утверждают, что одно или несколько защитных предложений — условные операторы возврата «раннего выхода» в начале функции — часто делают функцию более читаемой, чем альтернативу. [17] [18] [19] [20]

Самая распространенная проблема при раннем выходе заключается в том, что операторы очистки или заключительные операторы не выполняются — например, выделенная память не освобождается от распределения или открытые файлы не закрываются, что приводит к утечкам. Это необходимо делать на каждом участке возврата, поскольку он хрупкий и может легко привести к ошибкам. Например, на более поздних стадиях разработки разработчик может пропустить оператор возврата, а действие, которое должно быть выполнено в конце подпрограммы (например, оператор трассировки ), может выполняться не во всех случаях. Языки без оператора возврата, такие как стандартный Паскаль, не имеют этой проблемы. В некоторых языках, таких как C++ и Python, используются концепции, позволяющие автоматически выполнять действия при возврате (или выдаче исключения), что смягчает некоторые из этих проблем — их часто называют «попробуй/наконец» или им подобных. Функциональность, подобная этим предложениям «finally», может быть реализована путем перехода к единственной точке возврата подпрограммы. Альтернативное решение — использовать обычное развертывание стека (освобождение переменной) при выходе из функции для освобождения ресурсов, например, с помощью деструкторов локальных переменных или аналогичных механизмов, таких как оператор Python «with».

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

В Java — и подобных ему языках, таких как JavaScript , — можно выполнять код даже после оператора return, поскольку всегда выполняется блок «finally» структуры try-catch . Таким образом, если оператор return помещен где-то внутри блоков try или catch , код внутри него, наконец (если он добавлен), будет выполнен. Можно даже изменить возвращаемое значение не примитивного типа (свойство уже возвращенного объекта), поскольку выход также происходит позже. [21]

Отчеты о доходности

Двоюродным братом оператора return являются операторы доходности : если возврат приводит к завершению подпрограммы , то выход приводит к приостановке работы сопрограммы . Сопрограмма позже продолжит работу с того места, где она была приостановлена, если ее вызвать снова. Сопрограммы гораздо сложнее реализовать, чем подпрограммы, поэтому операторы доходности встречаются реже, чем операторы возврата, но они встречаются во многих языках.

Последовательности вызова/возврата

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

  1. Инструкция CALLпомещает адрес следующей инструкции в стек и переходит к указанному адресу. Инструкция RETURNизвлекает адрес возврата из стека в указатель инструкции, и выполнение возобновляется по этому адресу. (Примеры: x86 , PDP-11 ) В таких архитектурах, как Motorola 96000 , область стека может быть выделена в отдельном адресном пространстве, которое называется «Пространство памяти стека», [22] отличное от адресного пространства основной памяти. [23] NEC μPD7720 также имеет стек с собственным отдельным адресным пространством. [24]
  2. Инструкция CALLпомещает адрес следующей инструкции в регистр и переходит к указанному адресу. Последовательность RETURNкоманд помещает адрес возврата из регистра в указатель инструкции, и выполнение возобновляется по этому адресу. (Примеры: IBM System/360 и его преемники до z/Architecture , большинство RISC- архитектур)
  3. Инструкция CALLпомещает адрес следующей ( или текущей ) инструкции в ячейку памяти по адресу вызова и переходит к указанному адресу +1. Последовательность RETURNкоманд переходит к адресу возврата путем косвенного перехода к первой команде подпрограммы. (Примеры: IBM 1130 , SDS 9XX , PDP-8 )

Смотрите также

Примечания

  1. ^ в оболочке Bourne могут быть возвращены только целые числа в диапазоне 0–255 [11]

Рекомендации

  1. ^ ab "Заявление о возврате (C)". Документы Майкрософт . 25 января 2023 г.
  2. ^ ab «Оператор возврата (C++)». Документы Майкрософт . 3 августа 2021 г.
  3. ^ Гливс, Р. (2012). Модуль-2 для программистов на Паскале. Спрингер. п. 71. ИСБН 9781461385318.
  4. ^ abc Мартелли, Алекс (2006). Python в двух словах: краткий справочник по рабочему столу (2-е изд.). О'Рейли Медиа. п. 73. ИСБН 9781449379100.
  5. ^ аб Скотт, Майкл Л. (2006). Прагматика языков программирования. Морган Кауфманн. п. 432. ИСБН 9780126339512.
  6. ^ Фландрия, Харли (2012). Научный Паскаль. Спрингер. п. 35. ISBN 9781461224280.
  7. ^ ANSI x3.9-1966. Стандарт США FORTRAN (PDF) . Американский национальный институт стандартов. п. 14. Архивировано из оригинала (PDF) 15 мая 2011 года . Проверено 5 мая 2010 г.{{cite book}}: CS1 maint: числовые имена: список авторов ( ссылка )
  8. ^ ANSI x3.9-1978. Американский национальный стандарт – язык программирования FORTRAN. Американский национальный институт стандартов. 15.8 Оператор RETURN. Архивировано из оригинала 29 октября 2013 года . Проверено 11 декабря 2007 г.{{cite book}}: CS1 maint: числовые имена: список авторов ( ссылка )
  9. ^ Саккинен, Маркку (март 1989 г.). «Как лучше всего вернуть значение функции». Уведомления ACM SIGPLAN . 24 (3). Ассоциация вычислительной техники: 55–56. дои : 10.1145/66083.66087 .
  10. Вирт, Никлаус (3 мая 2016 г.). «10. Объявления процедур». Язык программирования Оберон (PDF) (Отчет). п. 11.
  11. ^ «возврат — возврат из функции или точечного скрипта». Единая спецификация UNIX .
  12. ^ «PHP: возврат — Руководство» . Руководство по PHP . Группа PHP . Проверено 26 марта 2013 г.
  13. ^ «Возвращение — Javascript». Справочник по Javascript MDN . Сеть разработчиков Mozilla . Проверено 27 марта 2013 г.
  14. ^ «Примечания по C++: оператор возврата функции» .
  15. ^ Ватт, Дэвид Энтони; Финдли, Уильям (2004). Концепции проектирования языков программирования . Джон Уайли и сыновья. стр. 215–221. ISBN 978-0-470-85320-7.
  16. ^ Робертс, Э. (март 1995 г.). «Выходы из цикла и структурированное программирование: возобновление дебатов». Бюллетень ACM SIGCSE . 27 (1): 268–272. дои : 10.1145/199691.199815 .
  17. ^ Мартин Фаулер; Кент Бек; Джон Брант; Уильям Опдайк; Дон Робертс (2012). Рефакторинг: улучшение дизайна существующего кода (электронная книга Google). Аддисон-Уэсли. стр. 237, 250. ISBN. 9780133065268. ... менталитет одной точки выхода ... Я не следую правилу об одной точке выхода из метода.
  18. ^ Кент Бек (2007). «7: Поведение». Шаблоны реализации. Пирсон Образование. раздел «Охранная статья». ISBN 9780132702553.
  19. ^ «Множественные операторы возврата» . Java-практики .
  20. ^ Фред Шварц. «Заявления о возврате и фантазия о единственном выходе». Архивировано из оригинала 23 февраля 2020 г.
  21. ^ «Наконец-то Блок». Учебники по Java .
  22. ^ «РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ 32-БИТНОГО ПРОЦЕССОРА ЦИФРОВЫХ СИГНАЛОВ DSP96002» (PDF) . п. 27(3 - ​​4) . Проверено 24 декабря 2023 г.
  23. ^ «РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ 32-БИТНОГО ПРОЦЕССОРА ЦИФРОВЫХ СИГНАЛОВ DSP96002» (PDF) . п. 50(4 - 11) . Проверено 24 декабря 2023 г.
  24. ^ «ЦВП μPD77C20A, 7720A, 77P20» . п. 4(3а-4) . Проверено 25 декабря 2023 г.