Глава 8. ПОДПРОГРАММЫ И МОДУЛИ Процедуры и функции Область видимости переменных Хранение локальных данных в памяти компьютера Формальные и фактические параметры Параметры-значения и параметры-переменные Особенности функций Опережающее описание Рекурсия Процедурные типы Параметры-функции и параметры-процедуры Стандартные математические функции и процедуры Модули Структура модуля Режимы компиляции модулей Стандартные модули
2 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Подпрограммы (процедуры или функции) представляют собой относительно самостоятельные фрагменты программы, оформленные особым способом и снабженные именем. Упоминание этого имени в тексте программы называется вызовом процедуры (функции). Program Calculator; Begin Initialize; DrawScreen; Calculation; RestScreen; End. Подпрограммы представляют собой инструмент, с помощью которого любая программа может быть разбита на ряд относительно независимых частей, что имеет смысл по двум причинам. Во-первых, это средство экономии памяти и других ресурсов: каждая подпрограмма существует в программе в единственном экземпляре, в то время как обращаться к ней можно многократно из разных точек программы. Во-вторых, при таком разбиении максимально реализуется принцип нисходящего проектирования. В этом случае алгоритм представляется в виде последовательности относительно крупных подпрограмм, реализующих более или менее самостоятельные смысловые части алгоритма.
3 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Структура подпрограммы Заголовок процедуры procedure список параметров идентификатор ; раздел операторов заголовок раздел описаний ; Заголовок функции function список параметров иденти- фикатор ; тип результата :
4 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Машинные команды, из которых состоит любая программа, хранятся в кодовом сегменте ОЗУ, адрес которого находится в регистре процессора CS. Выполнение про- граммы происходит путем последовательного чте- ния команд, начиная с первой; следующей вы- полняется команда, рас- положенная «выше» то- лько что выполненной ("естественный" порядок выполнения команд). Смещение относительно начала кодового сегмен- та, определяющее адрес Конец программы Конец RestScreen Начало RestScreen Начало Calculation Конец Calculation Конец DrawScreen Начало DrawScreen Конец Initialize Начало Initialize Вызов RestScreen Вызов Calculation Вызов DrawScreen Вызов Initialize Начало программы Младшие адреса Старшие адреса выполняемой команды, процессор хранит в регистре IP. Пара CS:IP указывает на текущую команду и называется активной точкой программы. Естественный порядок выполнения команд нарушается при обращении к подпрограммам.
5 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Адрес точки возврата (текущие значения СS:IP в момент вызова подпрограммы) хранится в ячейках специально выделенного сегмента ОЗУ, который называется стеком. Кроме того, стек в памяти используется для хранения значений локальных переменных подпрограммы во время выполнения операторов, входящих в ее тело. Принцип его работы совпадает с организацией динамической структуры данных, имеющей такое же имя – стек. Стек – это LIFO-устройство (Last In First Out). Значение сегмента стека SS и текущее значение указателя вершины стека SP (смещение относительно начала сегмента, которое указывает на уровень, разделяющий занятые и свободные ячейки) хранятся в соответствующих регистрах центрального процессора. Особенность заполнения стека в памяти состоит в том, что он заполняется сверху вниз, т.е. ячейки со смещением больше SP заняты, а меньше (низшие адреса) – свободны. После выполнения всех операторов подпрограммы стек освобождается для хранения данных следующей вызванной подпрограммы. В последнюю очередь считывается адрес команды, которая стоит после вызова выполненной подпрограммы в основном блоке (адрес точки возврата).
6 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Область видимости переменных Глобальные константы, типы, переменные – это те, которые объявлены в программе вне процедур или функций. Они доступны из любого места программы. Локальные – это константы, типы, переменные, существующие только внутри процедур или функций, и объявленные либо в соответствующих разделах Const, Type, Var внутри данной процедуры или функции, либо в списке формальных параметров (как параметры-значения). Глобальные переменные хранятся в сегменте данных, локальные – в стеке. Область видимости переменной (константы, типа) – это ряд операторов, в которых переменная "видна". Все имена, описанные внутри подпрограммы (локальные данные), локализуются в ней, т.е. они как бы "невидимы" снаружи подпрограммы. При наличии вложенных подпрограмм переменные данного уровня являются «видимыми», т.е. доступными для всех нижних уровней описания процедур. Подпрограммы, наряду со своими локальными данными, могут использовать и модифицировать и глобальные. Для этого лишь нужно, чтобы описание процедуры (функции) стояло в тексте программы ниже, чем описание соответствующих глобальных типов, констант и переменных. Время жизни переменной – это время, в течение которого переменная связана с определенной ячейкой памяти.
7 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Program Main; Var Xmain, Ymain : Integer; {глобальные переменные} Procedure P1; {описание процедуры} Var Res : Real; {локальная переменная} begin Res := 0.5; Ymain := Res + Xmain*Ymain; Xmain := Xmain + 1 end;... Var {глобальные переменные, недоступные в Р1) Zmain : Extended;... Begin... P1; {вызов процедуры}... End.
8 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Параметры Параметры обеспечивают обмен значениями между вызывающей частью программы и вызываемой подпрограммой. Параметры могут быть параметрами-значениями, параметрами-переменными или параметрами- константами. ( идентификатор ): тип параметра const var ;, Описываемые в заголовке подпрограммы параметры называются формальными: Procedure P1 (A : Integer; Var B : Real); а те, которые подставляются на их место при вызове - фактическими, т. к. они при выполнении как бы замещают все вхождения в подпрограмму своих формальных "двойников": Р1(A_fact,B_fact);
9 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Если параметр описан как параметр-значение, то в подпрограмму передается копия значения этого параметра, и никакие изменения этой копии не возвращается в вызывающий блок. Параметр-значение – это локальная переменная подпрограммы, стартовое значение которых задается при вызове подпрограммы из внешних блоков. Если параметр описан как параметр-переменная (служебное слово Var в заголовке) или как параметр-константа (слово Const), то в подпрограмму передаются адреса фактических параметров. Все изменения параметра- переменной в подпрограмме происходят с переменной, переданной в качестве фактического параметра. Параметр-константа не может изменяться в подпрограмме. На место фактического параметра-значения можно подставлять литерал, выражение, идентификатор (переменную или константу), а на место параметра-переменной и параметра-константы – только идентификатор.
10 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Сonst A : Integer = 5; {типизированные константы} B : Integer = 7; { - переменные} Procedure Plus (Var C : Integer; B : Integer); begin C := C + C; B := B + B; Writeln(C,B) end; Begin Writeln(A,B); Plus(A,B); Writeln(A,B) End. Свободные ячейки Адрес точки возврата Адрес переменной А в сегменте данных Значение В СТЕК (64 К) SP
11 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Функции Кроме обмена значениями через параметры функция возвращает в вызываемый блок свое значение в виде скаляра, строки или указателя. Для присвоения функции значения ее имя должно появиться хотя бы однажды в левой части оператора присваивания в теле самой функции. Функция имеет побочный эффект, если она производит другие действия, не связанные с вычислениями своего значения. Var {функция вычисления X Y } X,Y : Real; Function Power (Arg, P : Real) : Real; begin if Arg 0 then Power := exp(P * ln(abs(Arg))) else if P = 0 then Power := 1 else Power := 0 end; Begin Readln(X,Y);Writeln(Power(X,Y)) End.
12 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Опережающее описание Используется, в основном, для развязки закольцованных вызовов (одна подпрограмма вызывает вторую, которая в свою очередь вызывает первую). Procedure P1 ( ); forward; Procedure P2 ( );... begin... P1(...);... end; Procedure P1;... begin... P2(...);... end;
13 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Рекурсия Применительно к практическому программированию под рекурсией понимается вызов функции (процедуры) из тела этой же самой функции (процедуры). Необходимым условием работоспособности рекурсивных подпрограмм является наличие условия окончания рекурсивных вызовов. Var {вычисление n!} N : Word; Function Fact (m : Word) : LongInt; begin if m = 0 then Fact := 1 else Fact := m*Fact(m-1) end; Begin Readln(N); Writeln('n! = ',Fact(N)) End.
14 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Реализация рекурсивных алгоритмов при большом числе итераций ограничена доступным объемом памяти; каждый отложенный вызов процедуры или функции – это свой набор значений всех локальных переменных этой подпрограммы, размещенных в стеке. {вычисление n! итерационным методом} Function Fact (m : Word) : LongInt; Var I : Word; P : LongInt; begin P := 1; if m = 0 then Fact := 1 else begin for I := 1 to m do P:=P*I; Fact := P end end;
15 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Процедурный тип Процедурный тип позволяет интерпретировать процедуры и функции как данные-объекты, которые можно использовать, в частности, при передаче параметров. Значением переменной процедурного типа является конкретная процедура или функция. Type идентификатор типа =; procedure список параметров function список параметров тип результата :
16 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Параметры-функции и параметры-процедуры {вычисление интеграла функции} Type FuncType = Function (X : Real) : Real; Procedure Integral (LowerLimit, UpperLimit : Real; Var Result : Real; Funct : FuncType); begin... end; Function SinExp (Arg : Real) : Real; begin SinExp := Sin(Arg) + Exp(Arg) end; Var Res : Real;... Begin... Integral (0, 1, Res, SinExp);... End.
17 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Процедура – поле записи. Type ProcType = Procedure; RecType = record X,Y : Integer; P : ProcType; end; Var Rec1,Rec2 : RecType; Procedure P1; begin... end; Begin... with Rec1 do P := P1;... End.
18 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Стандартные математические функции и процедуры: ABS(X) – возвращает абсолютное значение аргумента Х (Х – целое/вещест- венное, результат – как у аргумента); SQR(X) – возвращает квадрат Х (Х – целое/вещественное, результат – как у аргумента); SIN(X), COS(X), ArcTan(X) – возвращают значения синуса, косинуса и арктангенса (Х – целое/вещественное, результат – вещественное); SQRТ(X) – возвращает квадратный корень из Х (Х > 0 – целое/вещественное, результат – вещественное); EXP(X), LN(X) – возвращает экспоненту или натуральный логарифм Х (Х – целое/вещественное, результат – вещественное); FRAC(X) – дробная часть числа Х (Х – целое/вещественное, результат – вещественное); INT(X) – целая часть числа Х (Х – целое/вещественное, результат – вещественное); TRUNC(X) – целая часть числа Х (Х – целое/вещественное, результат – целое (LongInt)); ROUND(X) – округление Х до ближайшего целого (Х – целое/вещественное, результат – целое (LongInt));
19 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ RANDOM(X) – возвращает случайное целое число из диапазона от 0 до Х (X и результат – Word); RANDOM – возвращает случайное число от 0 до 1 (результат – вещественный); RANDOMIZE – процедура гарантирует несовпадение последовательностей случайных чисел, выдаваемых функцией Random; ODD(X) – возвращает True, если Х – нечетное число, и False, если Х – четное (Х – целое, результат – логический); INC(Var X : ), DEC(Var X : ) – увеличивает или уменьшает значение Х на 1 (процедуры); INC(Var X : ; N : ), DEC(Var X : ; N : ) – увеличивает или уменьшает значение Х на N (процедуры); Var X : LongInt; Begin X := 2; INC(X,4) {X 6} End.
20 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Модули Модуль – это автономно компилируемая программная единица, включающая в себя различные компоненты раздела описаний (типы, константы, переменные, процедуры, функции) и, возможно, некоторые исполняемые операторы, которая предназначена для использования другими модулями и программами. Компилятор Тurbo Рascal размещает программный код каждого модуля в отдельном сегменте памяти. Unit ; Interface Implementation Begin End. Имя модуля (Unit Unit_1;) должно совпадать с именем дискового физического файла, в который помещается исходный текст модуля (unit_1.pas). Для подключения ресурсов модуля к другим программным единицам (программа, модуль) необходимо указать его имя в спецификации Uses раздела описаний этой программной единицы (Uses Unit_1;).
21 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Unit Unit_1; Interface Type Complex = record Re, Im : Real end; Var Zmain : Complex; Procedure P_1 (X,Y : Complex; Var Z : Complex); Implementation Procedure P_1; begin Z.Re := X.Re + Y.Re; Z.Im := X.Re + Y.Re end; Begin Zmain.Re := 1; Zmain.Im := -1 End.
22 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ В интерфейсной секции содержатся объявления всех глобальных элементов модуля (типов, констант, переменных, функций, процедур), которые должны стать доступными основной программе и другим модулям, к которым подключен данный модуль. При объявлении глобальных подпрограмм указывается только их заголовок. Если при объявлении типов, данных и подпрограмм используются элементы, введенные в других модулях, то они должны быть указаны в разделе Uses сразу после слова Interface. Секция реализации содержит описание подпрограмм, объявленных в интерфейсной части, и описание внутренних ресурсов модуля (локальных переменных, типов, подпрограмм). Обращение к этим ресурсам возможно только из подпрограмм, описанных в этом же модуле. Секция инициализации (может отсутствовать) открывается словом Begin, после чего следуют программные действия, которые будут произведены перед выполнением основной программы, к которой подключен данный модуль. Обычно в разделе инициализации происходит заполнение стартовыми значениями библиотечных переменных, а также одноразовые действия, которые должны выполниться в начале программы (например, открываться нужные файлы и т.д.).
23 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Режимы компиляции модулей COMPILE. Компилируется только основная программа. Все упоминающиеся в разделе Uses модули должны быть предварительно откомпилированы и результаты компиляции помещены в одноименные файлы с расширением.tpu (unit_1.tpu). Используется при отладке основной программы. MAKE. Модули, для которых не обнаружены tpu-файлы, компилируются из соответствующих файлов.pas. Кроме того, система следит за возможным изменением текста модуля. Если он изменялся, то независимо от существования tpu-файлов модуль компилируется заново. Упрощает процесс обработки многофайловых программ, когда компилируется только необходимый минимум. BUILD. Существующие tpu-файлы игнорируются и система пытается откомпилировать соответствующий pas-файл для каждого модуля.
24 Гл. 8. ПОДПРОГРАММЫ И МОДУЛИ Стандартные модули Turbo Pascal SYSTEM – включает все стандартные математические процедуры и функции, а также обеспечивает работу с командной строкой, ввод/вывод, эмуляцию сопроцессора, работу с динамической памятью, и т.д. (подключается к любой программе автоматически); CRT – содержит библиотеку процедур, которые работают с клавиатурой и дисплеем, обеспечивая текстовый режим работы экрана; DOS – в модуле собраны процедуры и функции, открывающие доступ к средствам ОС МS-DOS (обработка файлов, работа с каталогами, и т.д.); PRINTER – делает доступным вывод текстов на матричный принтер; GRAPH – содержит набор типов, данных и подпрограмм для управления графическим режимом работы экрана; OVERLAY – необходим при разработке больших программ, длина которых превышает память, отводимую MS-DOS под исполняемую программу; TURBO3, GRAPH3 – введены для совместимости с ранней версией Тurbo Рascal 3.0; Модули SYSTEM, DOS, CRT, PRINTER, OVERLAY входят в состав библиотечного файла turbo.tpl. Остальные выделены в отдельные tpu-файлы.