Лекция № 3.
Модули.
Модуль является программной единицей для хранения элементов, которые можно использовать в тех или иных программах. Такими элементами могут быть типы, константы, переменные и подпрограммы. Если все, что было написано в программе, полностью входит в скомпилированный файл программы, то из модуля в скомпилированную программу попадают только те части, которые необходимы данной программе. Поэтому модуль выступает как библиотека, которую можно употреблять во многих программах, и каждая из них берет только то, что ей требуется. Наличие модулей в Турбо-Паскале позволяет программировать и отлаживать программу по частям, создавать библиотеки подпрограмм и данных, пользоваться возможностями стандартных модулей, практически неограниченно увеличивать кодовую (содержащую коды команд) часть программы.
Все модули можно разбить на две группы:
- стандартные модули - заранее созданные разработчиками языка Turbo-Pascal 7.0 (эти модули поставляются в скомпилированном виде, и их без каких-либо доработок можно использовать в программах);
- модули пользователя - которые создает сам программист (он должен написать модуль, скомпилировать его, отладить и только после этого использовать в своей программе; естественно, что в такие модули программист при необходимости может вносить изменения).
Модуль состоит из следующих частей:
- заголовок модуля;
- интерфейс модуля;
- исполнительная часть модуля;
- секция инициализации.
Все разделы модуля, за исключением секции инициализации, являются обязательными. Обязательна также указанная последовательность разделов.
Заголовок модуля.
Заголовок модуля состоит из зарезервированного слова UNIT и идентификатора (имя модуля). Идентификатор модуля должен быть уникальным. Пример заголовка:
UNIT MyModule;
Модуль должен быть помещен в файл, имя которого совпадает с именем модуля, а его расширение должно быть .pas.
Интерфейс модуля.
Через интерфейс осуществляется взаимодействие основной программы с модулем (модуля с модулем). В интерфейсе указываются константы, типы, переменные, процедуры и функции, которые могут быть использованы основной программой (модулем) при вызове этого модуля.
Интерфейсная часть модуля начинается словом interface и может содержать следующие разделы:
- раздел объявления используемых модулей;
- раздел объявления констант;
- раздел объявления типов;
- раздел объявления переменных;
- раздел объявления процедур и функций.
Завершается интерфейсная часть началом исполнительной части.
Раздел объявления используемых модулей интерфейсной части модуля такой же, как у программы, а параметры модулей, перечисленных здесь, могут использоваться во всех частях модуля, а не только в интерфейсной части.
Если один модуль обращается к интерфейсной части другого, который в своей интерфейсной части обращается к третьему модулю и т.д., наконец, последний модуль использует первый модуль (так называемое циклическое использование модулей), то такая ситуация недопустима из-за того, что компилятор в этом случае не сможет установить необходимые связи.
Все разделы интерфейсной части, кроме раздела объявления используемых модулей, могут идти в любой последовательности; можно создавать несколько однотипных разделов.
В разделе объявления процедур и функций указываются лишь заголовки подпрограмм (за исключением тех подпрограмм, которые используют директиву inline, которая здесь допустима). Сами подпрограммы приводятся в исполнительной части модуля.
Исполнительная часть модуля.
Исполнительная часть включает все подпрограммы модуля. Она может также включать локальные метки, константы, типы и переменные, недоступные для других программных единиц (естественно, и для интерфейса самого модуля).
Начинается интерфейсная часть словом implementation, а завершается либо началом секции инициализации, если она есть, либо словом end. (с точкой).
Исполнительная часть - "внутренняя кухня" модуля, где протекают процессы, о которых не недо "знать" другим программным единицам. Она может содержать следующие разделы:
- раздел объявлений используемых модулей;
- раздел объявления констант;
- раздел объявления типов;
- раздел объявления переменных;
- раздел процедур и функций.
В разделе объявления используемых модулей исполнительной части перечисляются модули, параметры которых могут употребляться в модуле всюду, за исключением интерфейсной части (чаще всего так и бывает). В исполнительной части допускается циклическое применение модулей, поэтому по мере возможности именно здесь следует объявлять модули. Если какой-то модуль объявлен в интерфейсной части, то в исполнительной части его объявлять не следует. В остальном раздел объявления используемых модулей исполнительной части такой же, как и в интерфейсной части.
Все разделы исполнительной части, кроме раздела объявления модулей, могут идти в любой последовательности; можно создавать несколько однотипных разделов.
При описании процедур и функций в исполнительной части допустимо записывать их сокращенные заголовки (без перечисления формальных параметров). Если же здесь записываются полные заголовки, они должны быть полностью идентичны заголовкам в интерфейсной части.
Секция инициализации.
В некоторых случаях перед обращением к модулю следует провести его инициализацию (например, установить связи с теми или иными файлами с помощью процедуры Assign, инициализировать какие-то переменные и т.д.). Необходимые действия можно выполнить в секции инициализации модуля. Эта секция начинается словом begin, после которого идут исполняемые операторы, а заканчивается словом end. (с точкой), например:
Begin
C:=5; P:=3.14
End.
Следует иметь в виду, что операторы секции инициализации выполняются единственный раз в момент запуска программы.
Если инициализация модуля не нужна, то в секции помещается лишь слово end. (с точкой).
Использование модуля в основной программе.
Чтобы использовать подпрограммы, константы, типы, переменные, описанные в интерфейсе модуля, в основной программе следует поместить раздел объявления используемых модулей. Раздел состоит из одного предложения и начинается зарезервированным словом USES, после которого через запятую указываются имена модулей. После этого в основной программе можно использовать идентификаторы, указанные в интерфейсах перечисленных модулей.
Пример: Программа, меняющая в массиве максимальное и минимальное числа.
program Primer1; {Заголовок программы}
uses Unit1,Unit2; {Используемые модули}
var i:
integer;
begin
Change(Arr); {Процедура замены в Unit1, массив Arr - в Unit2}
for i:=1 to N do {N - в Unit2}
writeln(Arr[i])
end.
{Модули, расположенные в других файлах}
unit Unit1; {Модуль с основной подпрограммой}
interface {Интерфейс первого модуля}
uses Unit2; {Использование модуля с параметрами}
procedure Change(var Arr: Mass); {Заголовок процедуры}
implementation {Исполнительная часть}
uses Unit3; {Использование модуля со вспомогательной процедурой}
procedure Change; {Сокращенный заголовок}
var Max, Min, i: integer;
begin
Max:=1;
Min:=1;
for i:=1 to N do {N - в Unit2}
begin
if
Arr[i]>Arr[Max] then Max:=i;
if
Arr[i]<Arr[Min] then Min:=i
end;
Swap(Arr[Max], Arr[Min]) {Процедура
обмена - вUnit3}
end;
end. {Конец модуля Unit1}
unit Unit2; {Модуль, содержащий параметры}
interface {Интерфейс второго модуля}
const N=5; {Число элементов массива}
type Mass=array[1..N] of real; {Тип массива}
const Arr: Mass=(0.5, -2.0, 1.0, 3.5, 7.0); {Типизированная константа}
implementation {Исполнительная часть - пустая}
end. {Конец модуля Unit2}
unit Unit3; {Модуль со вспомогательной подпрограммой}
interface {Интерфейс третьего модуля}
procedure Swap(var X,Y: real);
implementation {Исполнительная часть}
procedure Swap(var X,Y: real); {Процедура обмена двух чисел}
var Z: real;
begin
Z:=X;
X:=Y; Y:=Z
end;
end. {Конец модуля Unit3}
Использование идентификаторов элементов модуля.
Как правило, идентификаторы объектов модуля используются в основной программе (или другом модуле) обычным образом. Однако может оказаться, что используемый идентификатор элемента модуля совпадает с идентификатором использующей его программы. Чтобы различить их, при обращении к элементу модуля используется его квалификатор, в качестве которого выступает имя модуля.
Пример: Использование одноименных идентификаторов.
program Primer2; {Заголовок программы}
uses Unit1;
var Result, X: real;
begin
read(X); {Чтение переменной программы}
read(Unit1.X); {Чтение переменной модуля}
Result:=X+Unit1.X
end.
unit Unit1; {Заголовок модуля}
interface
var X: real; {Переменная модуля}
implementation
end.
Компиляция программы, содержащей модули.
В процессе компиляции исходный (написанный в экранном редакторе) текст программы преобразуется к виду, доступному для вычислительной машины (получается код программы, состоящий из данных в двоичной форме и инструкций процессора). При этом, если программа состоит из отдельных частей, эти части объединяются в единое целое. Здесь же к программе добавляются подпрограммы из стандартных модулей и модулей пользователя.
В результате компиляции будет получена либо программа, находящаяся в оперативной памяти машины, либо программа, размещенная в файле на диске. Этот файл будет иметь то же имя, что и файл с исходным текстом программы, но с расширением EXE.
Файлы, содержащие модули, после компиляции получают расширение TPU.
Компиляция простейших программ, состоящих из одного файла, осуществляются с помощью команды меню Compile/Compile или комбинации клавиш Alt+F9 (только компиляция - без запуска программы на выполнение). В этом случае компилируется программа, находящаяся в активном окне редактирования.
Место размещения скомпилированной программы - в оперативной памяти или на диске - зависит от выбранного параметра, задаваемого командой меню Compile/Destination. В процессе отладки программу желательно компилировать в оперативную память, т.к. этот процесс происходит быстрее. Окончательный вариант программы желательно скомпилировать на диск с получением исполнимого файла, т.к. такой файл может быть запущен на выполнение без среды Turbo-Pascal. Кроме того, компиляция на диск может потребоваться и в том случае, если программа слишком велика и не помещается в оперативной памяти.
Сложные
программы, использующие модули, компилируются с помощью команд меню Compile/Build или Compile/Make (F9).
Перед
использованием этих команд необходимо предварительно задать имя основного файла
программы (с которого начнется компиляция), с помощью команды меню Compile/Primary file.
При компиляции программы с помощью команды Make, наряду с основным файлом перекомпилируются и те из файлов, используемых основной программой, исходные тексты которых были изменены к моменту компиляции. Если таких изменений не было, то тексты вспомогательных файлов не перекомпилируются.
При компиляции с помощью команды Build все используемые основной программой файлы перекомпилируются вместе с основной программой обязательно.
При компиляции с помощью команд Make и Build не обязательно загружать основной файл в окно экранного редактора (это касается и всех вспомогательных файлов). Если в процессе компиляции в одном из этих файлов будет обнаружена синтаксическая ошибка, этот файл будет автоматически отображен на экране в активном окне редактирования. Курсор при этом будет указывать место ошибки в тексте, а в служебной строке появится соответствующее сообщение об ошибке. Процесс компиляции при этом прекращается, объектный файл не создается. Компиляцию следует повторить после устранения ошибки.
Если компиляция завершилась успешно, на экран выдается соответствующее сообщение.
Стандартные модули.
Как отмечалось выше, модули можно использовать для создания библиотек стандартных подпрограмм и данных. В Turbo-Pascal 7.0 имеется большое количество стандартных подпрограмм и данных, объединенных в несколько стандартных модулей. Они позволяют упростить процедуру написания программ, более полно использовать возможности компьютера и операционной системы.
В библиотеке TP 7.0 имеются следующие стандартные модули:
- System - основная библиотека;
- Crt - для работы с консолью (TURBO.TPL);
- Dos - использование возможностей MS DOS (TURBO.TPL);
- Overlay - для организации оверлейных структур (TURBO.TPL);
- Printer - для работы с принтером (TURBO.TPL);
- Graph - графическая библиотека (GRAPH.TPU);
- Strings - для работы с ASCIIZ-строками (STRINGS.TPU);
- WinDos - использование возможностей MS DOS в сочетании с ASCIIZ-строками (WINDOS.TPU);
- Turbo3 - связь с программами Turbo Pascal 3.0 (TURBO3.TPU);
-
Graph3
- связь с графикой Turbo Pascal 3.0 (GRAPH3.TPU).
Использование стандартного модуля CRT.
Модуль CRT содержит константы, переменные, процедуры и функции, предназначенные для работы с консолью. Если стандартные процедуры ввода/вывода реализуются через операционную систему, то модуль CRT позволяет работать с BIOS и непосредственно с видеопамятью.
При работе с экраном через модуль CRT весь экран разбивается на отдельные строки, а каждая строка - на отдельные позиции, в каждую из которых можно поместить один символ (в том числе и пробел). Таким образом весь экран разбивается на отдельные неделимые прямоугольные элементы. Положение каждого элемента экрана определяется его координатами X (номер столбца, в котором расположен элемент) и Y (номер строки). Для каждого элемента можно задать цвет фона (задний план - BackGround) и цвет символа (передний план). Кроме того, символ можно сделать мерцающим. Вся эта информация - атрибуты символа - помещается в одном байте информации следующим образом:
Биты |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
М |
Ф |
Ф |
Ф |
С |
С |
С |
С |
Буквой М обозначен бит мерцания (символ мерцает, если в этом бите установлена 1), буквами Ф - биты, в которые записывается код цвета фона (биты 4-6), буквами С - биты, в которые помещается код цвета символа (биты 0-3).
Модуль CRT позволяет работать не только со всем экраном, но и выделять в нем прямоугольные окна. Любое окно задается своим левым верхним и правым нижним углом. Эти углы, так же как и положение любого объекта на экране задаются двумя координатами X и Y. При работе в окне координаты отсчитываются от левого верхнего угла окна. При запуске программы выделенное окно совпадает по размеру со всем экраном. По умолчанию установлен режим работы адаптера - 25 строк по 80 позиций в каждой, соответственно координаты такого окна - (1,1) и (80,25).
Коды цветов.
Black |
0 |
Черный |
Blue |
1 |
Синий |
Green |
2 |
Зеленый |
Cyan |
3 |
Голубой |
Red |
4 |
Красный |
Magenta |
5 |
Фиолетовый |
Brown |
6 |
Коричневый |
LightGray |
7 |
Светло-серый |
DarkGray |
8 |
Темно-серый |
LightBlue |
9 |
Светло-синий |
LightGreen |
10 |
Светло-зеленый |
LightCyan |
11 |
Светло-голубой |
LightRed |
12 |
Розовый |
LightMagenta |
13 |
Светло-фиолетовый |
Yellow |
14 |
Желтый |
White |
15 |
Белый |
Blink |
128 |
Мерцание символа |
Цвета с кодами от 0 до 7 включительно можно использовать как для символов, так и для фона. Остальные цвета и код мерцания можно использовать только для символов.
Процедуры модуля CRT.
ClrScr - Очистка экрана: процедура очищает текущее окно, заполняя его цветом фона, и помещает курсор в его верхний левый угол с координатами (1,1).
TextMode(Mode: Word) - задание текстового режима: устанавливает текстовый режим, заданный параметром Mode, увеличивает текущее окно до целого экрана. Некоторые значения параметра Mode:
0 |
40х25 черно-белый для цветного адаптера |
1 |
40х25 цветной для цветного адаптера |
2 |
80х25 черно-белый для цветного адаптера |
3 |
80х25 цветной для цветного адаптера |
TextBackground(Color: Byte) - задание цвета фона. Для того, чтобы все окно изменило цвет фона, необходимо после данной процедуры вызвать процедуру ClrScr, иначе будет изменяться лишь фон отдельных элементов при их вводе или выводе.
TextColor(Color: Byte) - задание цвета символов и параметра мерцания.
Window(x1,y1,x2,y2: Byte) - задает размеры окна на экране и помещает курсор в левый верхний угол окна с координатами (1,1).
Delay(Ms: Word) - Задает задержку выполнения программы в миллисекундах.
GotoXY(X,Y:Byte) - перемещает курсор к элементу экрана с заданными координатами (координаты отсчитываются от левого верхнего угла текущего окна).
DelLine - удаляет строку, в которой находится курсор.
InsLine - вставляет пустую строку на экране в месте расположения курсора и заполняет ее цветом фона.
Функции модуля CRT.
WhereX: Byte - возвращает текущую координату X курсора.
WhereY: Byte - возвращает текущую координату Y курсора.
Readkey: Char - считывает символ с клавиатуры.
KeyPressed: Boolean - анализирует нажатие клавиши клавиатуры (за исключением вспомогательных клавиш Shift, Alt, NumLock и т.п.). Результат - True, если клавиша на клавиатуре нажата, False - клавиша не нажата.
Пример: Установить текстовый режим 40х25 для цветного адаптера. Разместить в центре экрана окно, размерами 15х15. Установить цвет фона - голубой. Вывести в окне 5 раз слово "ПРИВЕТ" таким образом, чтобы текст в результате разместился по центру окна, и каждая строка была нового цвета. Определить позицию курсора и вывести результат в нижней строке окна слева. По нажатию любой клавиши необходимо вернуть экран в режим 2.