Модули
Модули предназначены для хранения стандартных готовых программ или наборов данных. В FPC поддерживаются:
- Модули общего назначения.
- Модули данных.
- Модули динамических библиотек.
Модуль включается в программу при компиляции. Это увеличивает память программы. DLL подключается в ходе выполнения программы при обращении к процедуре или функции, описанной в ней, только на время использования. Память почти не занимается. Модуль может хранить и подпрограммы и данные, а DLL – только подпрограммы.
Модуль общего назначения
Структура модуля
Программа в FPC состоит из главной программы и (возможно) нескольких модулей. Применение модулей позволяет:
- использовать метод бригадного программирования,
- сократить объем основной программы,
- при изменении подпрограммы перекомпилируется только она.
Модуль – хранилище стандартных готовых подпрограмм или данных. По своей структуре Модуль = Программа. Может храниться и компилироваться отдельно. Может использоваться другими программами или модулями путем вызова их подпрограмм по именам. Не используется автономно. Хранится в трех вариантах:
- Модуль на языке FPC, <имя>.pas.
- Компилированный ассемблерный модуль, <имя>.ppu.
- Компилированный объектный модуль, <имя>.o.
Структура модуля:
unit <имя>; // Заголовок модуля
interface
<Интерфейсная часть>
implementation
<Исполняемая часть>
initialization // Не обязательно
<Инициирующая часть>
finalization // Не обязательно
<Завершающая часть>
end.
Имя модуля обязательно, оно используется для связи с вызывающей программой. Должно совпадать с именем файла с кодом модуля на FPC. Ссылка на подключаемые модули в вызывающей программе размещается в строке: uses <список модулей>. Интерфейсная часть interface содержит:
- Ссылки на внешние модули, используемые в данном модуле.
- Объявления глобальных объектов (типов, констант, переменных).
- Заголовки (только) подпрограмм (функций и процедур).
Инициирующая часть initialization содержит инструкции, которые выполняются до передачи управления вызывающей программе. Например, инициируются переменные, открываются файлы и др. Завершающая часть finalization содержит инструкции, которые выполняются после завершения работы вызывающей программы. Например, освобождаются выделенные программе ресурсы, закрываются файлы и др.
Модуль комплексной арифметики
unit Complex; // Комплексная арифметика
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TComplex = record // Тип комплексного числа
Re, Im: Real
end;
function AddC(x,y: TComplex):TComplex; // Комплексное сложение
function SubC(x,y: TComplex):TComplex; // Комплексное вычитание
function MultC(x,y: TComplex):TComplex; // Комплексное умножение
function DivC(x,y: TComplex):TComplex; // Комплексное деление
implementation
function AddC(x,y: TComplex):TComplex;
begin
Result.Re:=x.Re + y.Re;
Result.Im:=x.Im + y.Im;
end;
function SubC(x,y: TComplex):TComplex;
begin
Result.Re:=x.Re – y.Re;
Result.Im:=x.Im – y.Im;
end;
function MultC(x,y: TComplex):TComplex;
begin
Result.Re:=x.Re*y.Re – x.Im*y.Im;
Result.Im:=x.Re*y.Im + x.Im*y.Re;
end;
function DivC(x,y: TComplex):TComplex;
var z: Real;
begin
z:=sqr(y.Re)+sqr(y.Im);
try // Защита при делении на 0
Result.Re:=(x.Re*y.Re + x.Im*y.Im)/z;
Result.Im:=(x.Re*y.Im – x.Im*y.Re)/z;
except // Если делитель 0, то
Result.Re:=1.1e309;
Result.Im:=1.1e309
end;
end;
end.
Динамически связываемая библиотека DLL
Введение
DLL = Dynamic Linked Library (Динамически связываемая библиотека). DLL – хранилище стандартных готовых подпрограмм. По своей структуре DLL = Программа. Хранится в двух вариантах:
- DLL на языке FPC, <имя>.pas. Это исходник.
- Компилированная DLL, <имя>.dll. Содержит объектный код.
Компилированный файл DLL должен быть доступен при выполнении. Код DLL не включается в программу. Он загружается в память при обращении к DLL, как параллельный процесс. Файл содержит объектные коды подпрограмм, доступ к которым осуществляется динамически при их вызове.
Одна и та же DLL может использоваться несколькими программами. Именно это является преимуществом использования DLL. В памяти имеется только один экземпляр библиотеки, к которому могут обращаться несколько программ. DLL содержит подпрограммы:
- Экспортируемые, они помечены словом Export.
- Внутренние.
Для обращения к подпрограмме используется внутренняя таблица, каждая строка которой содержит:
- Индекс (номер). Вызов по номеру более быстрый, но его программисту нужно помнить.
- Имя. Внутреннее для DLL.
- Внешнее имя. Это синоним внутреннего имени, имя в вызывающей программе.
- Адрес начала.
- Признак Resident. Если он установлен, то загруженная DLL остается резидентной, даже если счетчик С пуст.
Для DLL запрещено экспортировать данные, так как она может использоваться одновременно несколькими программами или модулями, при обращении которых к данным возможна конкуренция. DLL может создаваться и использоваться в программах на разных языках программирования. Доступ в ней к объектному коду. Поэтому нет зависимости от языка программирования DLL.
Структура DLL
library <имя>; // Заголовок
function MyFunc(<параметры>:<тип>;Export; // Функция экспорта
begin
<Тело функции>
end;
procedure MyProc;Export; // Процедура экспорта
begin
<Тело процедуры>
end;
exports // Списки экспорта
MyFunc,MyProc;
begin
<Инициирующая часть> // Часто пустая
end.
DLL содержит таблицу, в которой в строках с индексами, начиная от 0, находятся параметры подпрограммы (имя, внешнее имя, адрес начала, флаг Resident). Индекс можно задать:
- Неявно (не указывая его). Подпрограммы нумеруются, начиная с 0, по мере их появления в списках Exports.
- Явно, с использованием слова Index. Это рекомендуется, чтобы избежать путаницы.
В секции exports перечисляются экспортируемые подпрограммы с их признаками. Подпрограммы включаются в списки, которых может быть много (списки разделяются точкой с запятой). В каждом списке экспортируемые подпрограммы отделяются запятыми.
Для каждой подпрограммы в списке обязательно указывается ее имя. После имени можно указывать дополнительные данные, имеющиеся во внутренней таблице DLL: слово Index, за которым следует номер, слово Name, за которым следует внешнее имя, признак Resident. Дополнительные данные могут следовать в любом порядке. Ключевые слова отделяются пробелами. Примеры оформления фразы exports:
exports
MyFunc index 1,
MyProc index 2; // Явно добавлены номера после слова Index
exports
MyFunc name ‘NewFunc’; // После слова Name задано иное внешнее имя
exports
MyFunc Resident; // Установлен признак Resident
Вызывающая программа может вызвать подпрограмму:
- По имени. Это медленно. Имен много и они длинные. Время затрачивается на поиск имени в таблице имен DLL.
- При вызове по имени можно ускорить обращение, добавив слово Resident.
- По индексу, это быстрее. Позиция в таблице выбирается сразу.
DLL комплексной арифметики
Подпрограммы такие же, как в ранее рассмотренном модуле комплексной арифметики. Их внешние имена такие же, а внутренние имена другие.
library DLL_Complex; // Заголовок DLL
type // Глобальный тип. Не экспортируется
TComplex= record // Запись
Re,Im:real; // Два поля – вещественные числа
end;
function CAdd(x,y:TComplex):TComplex;export; // Функция сложения
begin
Result.Re:=x.Re+y.Re;
Result.Im:=x.Im+y.Im;
end;
function SubC(x,y:TComplex):TComplex;export; // Функция вычитания
begin
Result.Re:=x.Re–y.Re;
Result.Im:=x.Im–y.Im;
end;
function CMult(x,y:TComplex):TComplex;export; // Функция умножения
begin
Result.Re:=x.Re*y.Re–x.Im*y.Im;
Result.Im:=x.Re*y.Im+ x.Im*y.Re;
end;
function CDiv(x,y: TComplex):TComplex;export; // Функция деления
var z:Real; // Вспомогательная локальная переменная
begin
z:=sqr(y.Re)+sqr(y.Im); // Расчет знаменателя
try // Защита от краха при делении на ноль
Result.Re:=(x.Re*y.Re+x.Im*y.Im)/z;
Result.Im:=(x.Re*y.Im–x.Im*y.Re)/z;
except
Result.Re:=1.1e309; // При делении на 0 ответ очень большой
Result.Im:=1.1.e309;
end;
end;
end;
exports
CAdd index 1 ‘AddC’ resident,
CSub index 2,
CMult index 3,
CDiv index 4;
begin
end.