изменения данных в вызывающей программе. С другой стороны, если
вызываемая программа принимает адрес данных, по которому программа
затем может изменять данные, возможно изменение функционирования
вызывающей программы. Данные, передаваемые по значению, рассматри-
ваются затем как защищенные, а данные, передаваемые по адресу,
рассматриваются как подвергаемые риску.
Удивительно, что переменные, передаваемые в регистр, иногда
рассматриваются как передаваемые по адресу, поскольку регистры в
аппаратных средствах являются простыми специализированными адре-
сами. Это различие делается потому, что данные в регистрах под-
вержены риску, если подпрограмма или функция изменят данные в ре-
гистре и это повлияет на основную программу.
Относительно степени подверженности данных постороннему воз-
действию отсутствуют жесткие и прочные правила. Такие понятия,
как "передача по значению" и "передача по адресу" могут помочь
оценить ситуацию, но действительное решение по использованию типа
передачи зависит от того, насколько ценны данные для вызывающей
программы (степень риска), и имела ли доступ вызываемая программа
к первоначальным данным. Это в действительности определяет на-
сколько большая защита требуется для этих данных.
- 2-18 -
Функции в сравнении с подпрограммами
Это сравнение часто требуется для вызываемой программы, при
возврате новых данных в вызывающую программу. Как было отмечено
ранее, те программы, которые возвращают значения, называются
функциями, а программы, не возвращающие значения, - подпрограмма-
ми. В языках высокого уровня функции ограничиваются возвратом
только одного значения. Любая другая информация, возвращаемая в
вызывающую процедуру, передается обратно путем модификации одного
или нескольких параметров. В языке Ассемблер применяются другие
ограничения. Рассмотрим эти опции.
Возврат значений в регистрах
Простейшим способом возврата значения является способ возвра-
та значения в регистре. Как и при передаче параметров, эта опция
может быть ограничена количеством доступных регистров и размером
возвращаемых данных. Положительным моментом этого способа возвра-
та является то, что данные легко доступны и могут быть легко про-
верены или использованы.
Возврат значения в регистре имеет смысл для часто вызываемых
функций. Это не требует специальной установки и предварительной
подготовки буферов и пр. Большинство функций MS-DOS возвращает
свои значения этим способом. Однако, если все функции в программе
возвращают свои данные через регистры, то придется столкнуться с
задачей "большой бухгалтерии и перемешивания". Кроме этого, в
связи с тем, что регистры являются элементами, в которых произво-
дится большинство вычислений, налицо жесткая конкуренция по их
использованию.
Чаще всего регистры должны использоваться для небольших, час-
то используемых вызываемых программ, возвращающих немного значе-
ний и для программ, возвращаемые значения которых должны немед-
ленно подвергаться вычислениям. Одним из примеров этого случая
могла бы быть функция чтения символьных значений и преобразования
их в числовые значения.
Большинство языков высокого уровня для возвращаемых значений
используют различные технические приемы. Так, для возврата байто-
вого значения или значения, длиной в слово, обычно используется
регистр AX. Если необходимо возвратить значение, длиной в двойное
слово, такое как указатель far (далекий), то младшее значащее
слово (или часть смещения) возвращается в регистре AX, а старшее
значащее слово (или часть сегмента) возвращается в регистре DX. В
тех случаях, когда в вызывающую программу необходимо возвратить
более двух слов, данные помещаются в буфер памяти, а указатель на
этот буфер возвращается в вызывающую программу. Способы управле-
ния этим указателем зависят от конкретного языка.
Возврат значений в общей области
Возврат значений в общей области необходим для функций. Для
этого используется метод "стороннего эффекта", представляющий ра-
зумное, простое средство для возврата большого количества данных.
Методом стороннего эффекта он назван потому, что операция переда-
чи не сразу очевидна из прочтения раздела "вызов" вызывающей
программы и происходит как случайный результат процедуры. Так как
это не очевидно из вызова, то для ясности в документацию необхо-
- 2-19 -
димо добавить описание того, какие значения возвращаются и поче-
му.
В связи с этим, если вместо параметра в регистре или стеке
передается адрес общей области, то ожидаемые в этой отдельной об-
ласти памяти возвращаемые значения становятся более очевидными
для читателя. Кроме того, получается преимущество общности, т.к.
процедура может непосредственно возвращать свои значения в любую
ячейку буфера.
Возврат значений в стеке
Последним способом возврата значений является помещение их в
стек. Эта операция требует использования регистра BP для адреса-
ции стека (таким же способом, как передача параметров в стек).
При возврате значений, значения загружаются в стек в одну из яче-
ек памяти выше адреса возврата. Если процедура вызывается с пара-
метрами, то для сохранения возвращаемого значения может быть ис-
пользована одна из ячеек параметров. Если процедура вызывается
без параметров, то вызывающая процедура должна поместить в стек
фиктивный аргумент, чтобы отвести место для возвращаемого значе-
ния.
При возврате значений в стек вызываемая программа не должна
очищать стек с помощью инструкции RET N. Вместо этого вызывающая
процедура должна использовать для очистки стека получение возвра-
щаемых значений через простые инструкции POP (восстановление сло-
ва из стека).
Если возвращаемые значения слишком большие для удобного рас-
положения в стеке, то вызываемая программа может возвратить ука-
затель на ячейку памяти, где находится действительное возвращае-
мое значение. В этом случае вызывающая программа должна принять
решение о месте области буфера.
Отчеты об исключительных ситуациях
Здесь рассматривается индикация о состоянии возврата или об
обнаруженных и выдаваемых ошибках. Во многих прикладных програм-
мах одной из требуемых опций является необходимость иметь вызыва-
емые процедуры, функции и подпрограммы, обеспечивающие некоторые
типы индикации об ошибках или кодах состояния. Вероятно, читатель
уже заметил, что большинство функций MS-DOS вызывает возврат ко-
дов состояния о завершении. Часто для индикации наличия ошибки
используется бит переноса в одном или более регистрах, обычно в
регистре AX, содержащем подробную информацию о типе ошибки.
Бит переноса используется для номера причины. Его легко про-
верить (с помощью инструкций JC - переход, если был перенос, или
с помощью инструкции JNC - переход, если не было переноса); легко
установить, дополнить или очистить (с помощью инструкций STC -
установка флажка переноса, CMC - дополнение флажка переноса и CLC
- сброс флажка переноса); а также можно сохранить и восстановить
(с помощью инструкций PUSHF - запоминание флажков в стеке и POPF
- извлечение флажков из стека). Доступ к флажку переноса более
совершенен чем доступ к любому другому биту состояния в архитек-
туре микропроцессоров 8086/8088. Это сочетание обеспечивает иде-
альный механизм для индикации наличия исключительной ситуации.
Конечно, программист должен помнить об очистке бита переноса для
индикации нормального завершения в случае, если ошибка не прои-
зошла, потому что бит переноса может быть уже установлен при вы-
- 2-20 -
полнении обычной операции.
После того, как вызывающая программа обнаружит, что возникла
ошибка, программа должна установить природу ошибки. Иногда после-
дующая информация не требуется. Если требуется дополнительная ин-
формация, то для полного кода полезен выделенный регистр. Логично
выбрать регистр AX, но в связи с тем, что от этого регистра зави-
сит так много других операций (например, MUL - умножение аккуму-
лятора на операнд и DIV - деление аккумулятора на операнд), он
может оказаться недоступным. Какой бы регистр не выбирался, он
должен содержать не только код ошибки, но также и код нормального
завершения. В случае, если первичная информация об ошибке потеря-
на, программа может повторно проверить регистр для получения сос-
тояния завершения. Если информация критическая, выберите значение
для нормального завершения, которое является ненормальным резуль-
татом. Это означает, нельзя использовать значение нуля для нор-
мального завершения, потому что другая ошибка может легко почис-
тить код состояния. MS-DOS обеспечивает обслуживание отчетов об
ошибках для использования с программами, выполняющими другие
программы. Если подпроцесс хочет вернуть код ошибки в процесс,
который вызывал этот подпроцесс, он может поступить так, как
часть функционального вызова процесса завершения - функция 4Сh.
Затем порождающий процесс может получить этот код возврата через
функцию MS-DOS 4Dh. Затем можно получить код возврата порожденно-
го процесса. Этот механизм используется только с программами, вы-
полняемыми под управлением функции 4Bh - функции загрузки и вы-
полнения программы.
Типы кодирования
Для большинства основных программ на любом языке программиро-
вания программист редко интересуется подробностями выполнения
программы процессором. Подробности обработки в/в, управления па-
мятью, размещения программы в памяти при ее выполнении, как пра-
вило, предоставляются для управления операционной системе. Одна-
ко, имеется ряд моментов, когда требуется более непосредственное
управление программной средой. В эти моменты программисту может
потребоваться знание и готовность принять ответственное решение
по вопросам механизма загрузки, размещения и выполнения програм-
мы. Примерами, когда это требуется, могут служить: написание ав-
тономных программ, функционирующих без присутствия MS-DOS; под-
держка оверлейных (перекрываемых) программ для использования
больших программ в ограниченной физической памяти; и написание