Библиотека программиста

«Программирование, как и любовь - это одно слово, за которым скрывается бесчисленное множество занятий»

Главная страница > Язык Object Pascal > 18. Описания подпрограмм

18. Описания подпрограмм

Особенности функций.

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

function MyFunction: Integer;

begin

MyFunction := 5;

Result := Result * 2;

MyFunction := Result + 1;

end;

вернет значение 11.

Вместе с тем между именем функции и Result есть отличие. Оно иллюстрируется следующим примером:

function Power(X: Real; Y: Integer): Real;

var

I: Integer;

begin

Result := 1.0;

I := Y;

while I > 0 do

begin

if Odd(I) then Result := Result * X;

I := I div 2;

X := Sqr(X);

end;

end;

Если выполнение функции заканчивается без присваивания Result или имени функции какого-либо значения, то возвращаемое значение является неопределенным.

Соглашения по вызовам.

При объявлении функции или процедуры можно определить тип ее вызова с помощью одной из директив register, pascal, cdecl, stdcall и safecall. Например:

function MyFunction(X, Y: Real): Real; cdecl;

Тип вызова (calling conventions) определяет порядок передачи фактических параметров, а также использование регистров. Тип вызова влияет также на очистку стека по выходу из подпрограммы, обработку ошибок и исключительных ситуаций. По умолчанию тип вызова – register.

Директивы register и pascal определяют порядок передачи параметров слева направо, так что самый левый (фактический) параметр вычисляется и передается первым. Директивы же cdecl, stdcall и safecall определяют передачу параметров в противоположном направлении, т.е. справа налево.

Все директивы, кроме cdecl, указывают на необходимость удаления параметров из стека перед возвратом управления вызывающей программе. Директива cdecl указывает на то, что очистку стека выполняет вызывающая программа после получения управления от подпрограммы.

Директива register предполагает использование до трех регистров процессора для передачи параметров, в то время как другие директивы передают все параметры через стек.

Директива safecall обеспечивает обработку ошибок и исключений для COM.

Соглашения по вызовам

Директива

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

Где очищается стек

Передача параметров через регистры процессора

register

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

В подпрограмме

Да

pascal

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

В подпрограмме

Нет

cdecl

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

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

Нет

stdcall

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

В подпрограмме

Нет

safecall

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

В подпрограмме

Нет

Использование соглашения по вызовам register наиболее эффективно, так как обычно позволяет избежать создания стекового фрейма при вызове подпрограммы.

Соглашение cdecl полезно при вызове функций из DLL, написанных на языках С или С++, в то время как stdcall и safecall используются для вызовов функций Windows API.

Директива safecall должна использоваться для объявления методов двойственных (дуальных) интерфейсов (dual-interface methods). Дуальный интерфейс поддерживает как связывание на этапе компиляции, так и связывание на этапе выполнения. В этом случае параметры методов и возвращаемые функциями результаты должны иметь "автоматически обрабатываемые типы" (automatable types): Smallint, Byte, Integer, Currency, Single, Real, Double, Real48, AnsiString, ShortString, TDateTime, Variant, OleVariant и WordBool.

Директивы near, far и export относятся к соглашениям по вызовам для 16-битовой платформы Windows, используются для обратной совместимости и не имеют значения для 32-битовых приложений.

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

Директива external предназначена для вызова подпрограмм, которые откомпилированы отдельно, например, написаны на другом языке, и содержатся в объектных файлах. Для использования такой подпрограммы надо сначала подключить объектный файл с помощью директивы $L (или $LINK), например, {$L BLOCK.OBJ}. Затем необходимо описать подключаемую подпрограмму, например:

procedure MoveWord(var Source, Dest; Count: Integer); external;

procedure FillWord(var Dest; Data: Integer; Count: Integer); external;

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

Импорт подпрограмм из DLL.

Для подключения подпрограммы из динамически загружаемой библиотеки необходимо вслед за описанием заголовка подпрограммы поместить директиву external и имя файла, в котором находится DLL, например:

function SomeFunction(S: string): string; external 'strlib.dll';

Можно также импортировать подпрограмму под другим именем, указав настоящее имя подпрограммы в той же директиве external, например:

function MessageBox(HWnd: Integer; Text, Caption: PChar; Flags: Integer):
Integer; stdcall; external 'user32.dll' name 'MessageBoxA';

При указании имени подпрограммы в директиве external надо в точности соблюдать регистр символов. Вместо имени подпрограммы можно также указать ее номер в библиотеке (индекс).





<< Предыдущая статья
«17. Константы»
Следующая статья >>
19. Перегрузка подпрограмм