Главная » Free Pascal » Подпрограммы — процедуры и функции Free Pascal

0

Подпрограммы — один из наиболее ранних приемов автоматизации про- граммирования. Если алгоритм решения задачи содержит фрагменты, которые могут быть использованы не один раз в нескольких местах программы, то такие фрагменты можно выделить в программные единицы (процедуры или функции). Обращение к однажды написанному фрагменту программы с заданием новых входных данных (параметров программной единицы) позволяет существенно с о- кратить общий объем программы. Хорошо отработанный фрагмент типового ал- горитма может оказаться полезным и при решении других задач. Его можно ав- тономно протранслировать и включить в состав библиотеки подпрограмм, которые по мере надобности могут вызываться вашей программой и использо- ваться наравне с системными функциями и процедурами. По идеологии Паскаля библиотеки подпрограмм оформляются в виде модулей — файлов с расширением tpu (от Turbo Pascal Unit).

Оформление процедур

Объявление процедуры начинается с заголовка, имеющего в общем виде сле- дующий формат:

procedure name_proc[(list_arg)];[directives;]

Здесь:

± procedure — служебное слово;

± name_proc — имя процедуры;

± list_arg — необязательный список параметров;

± directives — одна или несколько уточняющих директив.

Директивы, уточняющие типы и способы передачи параметров, могут распола- гаться в разных местах заголовка — сразу после служебного слова procedure, пе- ред именем параметра в списке list_arg, в конце заголовка.

Квадратные скобки в заголовке процедуры свидетельствуют о необязательном присутствии того или иного компонента. Список параметров содержит информа-

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

clrscr;   {имя – аббревиатура от Clear Screen}

Некоторые параметры в списке аргументов представляют исходные данные, необходимые для работы процедуры. Их обычно называют входными данными. Другие параметры могут быть представлены переменными, в которые процедура заносит результаты своей работы. Это — так называемые выходные данные. Неко- торые параметры могут совмещать обе функции — сначала их значения использу- ются как входные данные, и в них же формируются результаты работы процедуры.

Список параметров принято называть списком формальных аргументов. Тер- мин "формальный" подчеркивает, что за обозначением параметра не скрывается какое-либо конкретное (фактическое) значение. Значения входных параметров превращаются в фактические аргументы только в момент обращения к процедуре. Выходные параметры приобретают конкретные значения в процессе выполнения процедуры.

Форма представления параметров в списке определяет их имена, типы соот- ветствующих данных и способы обмена между подпрограммой и вызывающей программой. В качестве разделителя между параметрами разного типа в заголовке процедуры используется точка с запятой. Имена двух или более параметров одно- го типа обычно объединяют в общее описание, разделяя их запятыми в заголовке процедуры. Например, заголовок процедуры, осуществляющей обмен данными между двумя областями оперативной памяти, может быть оформлен следующим образом:

procedure swap(var a,b; size:word);

В списке аргументов представлены три параметра с именами a, b и size. Два первых параметра передаются по адресам, определяющим начальное местополо- жение соответствующих областей оперативной памяти. Об этом свидетельствует директива var (от англ. variable — переменная). Тип параметров a и b не задан — в таких случаях принято говорить о нетипизированных параметрах. Третий пара- метр size, имеющий тип word, передается по значению (об этом свидетельствует отсутствие какой-либо директивы перед именем формального параметра). Он задает размер в байтах областей оперативной памяти, участвующих в обмене. В зависимо- сти от типа формальных параметров и способа их передачи вызывающая програм- ма должна использовать фактические аргументы, совместимые с соответствующим формальным параметром. В приведенном примере в качестве фактических значе- ний, соответствующих параметрам a и b, могут выступать имена данных любого типа. Фактическим аргументом, соответствующим параметру size, может быть любое выражение типа word или совместимое с этим типом по присваиванию (на- пример, типа byte).

Механизм передачи параметров унифицирован в большинстве систем про- граммирования. Он определяет следующие моменты:

± порядок передаваемых параметров;

± признак передаваемых данных;

± физический носитель данных, в который помещаются передаваемые параметры;

± способ восстановления физического носителя.

В системах программирования на базе языка Паскаль принят прямой порядок передачи параметров — слева направо по списку аргументов. В системах програм- мирования на базе языков C и C++ порядок передачи параметров обратный — справа налево. При составлении программ, использующих подпрограммы, на раз- ных алгоритмических языках, с этим обстоятельством приходится считаться и при- нудительно устанавливать тот порядок, который удовлетворяет вызываемую про- цедуру. Директива pascal заставляет компилятор использовать прямой порядок передачи параметров, директива cdecl (аббревиатура от C Declaration) является указанием об обратном порядке передачи параметров. В рамках программы ис- пользующей процедуры, написанные только на языке Паскаль, прибегать к указан- ным директивам смысла не имеет — по умолчанию действует режим, характерный для Паскаля.

В качестве признака передаваемых данных действует одно из следующих ука- заний:

± параметр является типизированным значением (имени параметра не предшест- вует ни одна директива);

± параметр передается по адресу (директива var), и его значение в процедуре может быть изменено;

± параметр передается как константа (директива const), и его имя в процедуре не может находиться в левой части оператора присваивания (т. е. параметр можно использовать только как входной). Параметр с указанием const переда- ется по адресу;

± параметр объявлен выходным (директива out), и его имя в процедуре может находиться только в левой части оператора присваивания. Выходной параметр передается по адресу.

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

В системах программирования на IBM-совместимых компьютерах используют- ся два основных физических носителя для передачи параметров — через стек и через машинные регистры.

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

но продвинуть содержимое регистра стека. Для этой цели система машинных команд предусматривает специальную операцию PUSH (от англ. push — затолк- нуть). Вторая машинная операция POP (от англ. pop up — выскочить наверх) позво- ляет извлечь из стека очередную порцию данных с одновременной коррекцией ре- гистра стека. Системная программа, обслуживающая стек, следит за тем, чтобы стек не переполнился при записи и не оказался пустым при извлечении данных. Иногда механизм работы стека сравнивают с магазином огнестрельного оружия — в нем пуля, попавшая последней в рожок автомата, стреляет первой. Этим же объ- ясняется технология обслуживания стека LIFO (Last Input — First Output, т. е. по- следним вошел — первым вышел). Зарядка магазина имитирует запись в стек, а процедура стрельбы напоминает извлечение данных из стека.

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

Таблица 9.1

Директива

Порядок передачи параметров

Кто чистит стек?

pascal

Слева направо

Вызываемая процедура

cdecl

Справа налево

Вызывающая программа

stdcall

Справа налево

Вызываемая процедура

safecall

Справа налево

Вызываемая процедура

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

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

Режим передачи параметров через регистры диктуется директивой register. Компилятор воспринимает это указание, как необязательное, и может установить соответствующий режим при соблюдении двух условий. Во-первых, количество передаваемых параметров должно быть не более трех, во-вторых, у компилятора имеется возможность освободить нужное количество регистров. Формирование адресов и/или значений фактических аргументов в регистрах сокращает время пе- редачи и извлечения параметров, тем самым повышая скорость работы процедуры.

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

   Листинг 9 .1 .  Пе ре множ е ние  к вад ра тных  ма триц                                                                         

const

N = 10;

type

matN = array [1..N,1..N] of double;

var

a,b,c : matN;

procedure mat_mult(A,B:matN; var C:mat_N); var

i,j,k: byte; s: double;

begin

for i:=1 to N do for j:=1 to N do begin

s:=0;

for k:=1 to N do s:=s+A[i,k]*B[k,j];

C[i,j]:=s; end;

end;

Нормальным завершением работы процедуры считается выход на завершаю- щий end. Досрочный возврат из процедуры реализуется с помощью оператора exit (выход).

Источник: Кетков, Ю. Л., Свободное программное обеспечение. FREE PASCAL для студентов и школьников, Ю. Л. Кетков, А. Ю. Кетков. — СПб.: БХВ-Петербург, 2011. — 384 с.: ил. + CD-ROM — (ИиИКТ)

По теме:

  • Комментарии