В общем случае использование процедурной переменной в опера-
торе или выражении означает вызов процедуры или функции, храня-
щейся в этой переменной. Однако, имеется исключение. Когда компи-
лятор видит, что процедурная переменная находится в левой части
оператора присваивания, он знает, что правая часть должна предс-
тавлять собой процедурное значение. Рассмотрим в качестве примера
следующую программу:
type
IntFunc = function: Integer;
var
F: IntFunc;
N: Integer;
function ReadInt: Integer; far;
var
I: Integer;
begin
Read(I);
ReadInt := I;
end;
begin
F := ReadInt; { присваивание процедурного значения }
N := ReadInt; { присваивание результата функции }
end.
Первый оператор основной программы присваивает процедурное
значение (адрес процедуры) ReadInt процедурной переменной F, вто-
рой оператор вызывает ReadInt и присваивает N возвращаемое значе-
ние. Различие между получением процедурного значения или вызовом
функции осуществляется по типу переменной, которой присваивается
значение (F или N).
К сожалению, есть ситуации, когда компилятор не может опре-
делить из контекста желаемое действие. Например, в следующем опе-
раторе для компилятора не очевидно, что нужно сделать: сравнить
процедурное значение в F с процедурным значением ReadInt, чтобы
определить, что F указывает в данный момент на ReadInt, или выз-
вать F и ReadInt, а затем сравнить возвращаемые значения:
if F = ReadInt then
WriteLn('Equal');
Однако, стандартный синтаксис Паскаля определяет, что вхож-
дение в выражение идентификатора функции означает вызов этой
функции, поэтому в результате предыдущего оператора будет выпол-
нен вызов F и ReadInt, а затем будут сравниваться возвращаемые
значения. Чтобы сравнить процедурное значение в F с процедурным
значением в ReadInt, нужно использовать следующую конструкцию:
if @F = @ReadInt then
WriteLn('Equal');
При применении к процедурной переменной, идентификатору про-
цедуры или функции операции получения адреса @, эта операция пре-
дотвращает вызов компилятором процедуры и в то же время преобра-
зует аргумент в указатель. Таким образом, @F преобразует F в не-
типизованный указатель-переменную, которая содержит адрес
ReadInt. Для определения того, что F ссылается на ReadInt можно
сравнить два значения-указателя.
Операция @ часто используется при присваивании процедурной
переменной нетипизированного значения-указателя. Например, опре-
деленная в Windows (в модуле WinProcs) функция GetProcAddress
возвращает адрес экспортируемой функции в DLL как нетипизирован-
ной значение-указатель. С помощью операции @ вызов GetProcAddress
можно присвоить процедурной переменной:
type
TStrComp = function(Str1, Str2: PChar): Integer;
var
StrComp: TStrComp:
.
.
.
begin
.
.
.
@StrComp := GetProcAddress(KernelHandle, 'Lstrcmpi');
.
.
.
end.
Чтобы получить адрес в памяти процедурной переменной, а не
адрес, в ней записанный, используйте двойную операцию @ (@@).
Например, @P означает преобразование P в нетипизированный указа-
тель-переменную, в @@P означает возвращение физического адреса
переменной P.