Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Паскаль / tp3 / tp3 / 8

.doc
Скачиваний:
16
Добавлен:
10.12.2013
Размер:
107.52 Кб
Скачать

function Equal(var source,dest; size: word): boolean;

type

Bytes = array[0..MaxInt] of byte;

var

N: integer;

begin

N := 0;

while (N<size) and (Bytes(dest)[N] <> Bytes(source)[N]

do Inc(N);

Equal := N = size;

end;

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

type

Vector = array[1..10] of integer;

Point = record

x,y: integer;

end;

var

Vec1, Vec2: Vector;

N: integer;

P: Point;

и вызовов функций:

Equal(Vec1,Vec2,SizeOf(Vector))

Equal(Vec1,Vec2,SizeOf(integer)*N)

Equal(Vec[1],Vec1[6],SizeOf(integer)*5)

Equal(Vec1[1],P,4)

сравнивается Vес1 с Vес2, сравниваются первые N элементов Vес1 с первыми N элементами Vес2, сравниваются первые 5 элементов Vес1 с последними пятью элементами Vес2 и сравниваются Vес1[1] с Р.х и Vес2[2] с P.Y.

Процедурные типы

Являясь расширением стандартного Паскаля, Турбо Паскаль позволяет интерпретировать процедуры и функции, как объекты, которые можно присваивать переменным и передавать в качестве параметров. Таким образом, допускается использование процедурных типов.

Примечание: Процедурные типы определяются также в Главе 3 ("Типы").

Процедурные переменные

После определения процедурного типа появляется возможность описывать переменные этого типа. Такие переменные нызывают процедурными переменными. Например, с учетом описаний типа из предыдущего примера, можно объявить следующие переменные:

var

P: SwapProc;

F: MathFunc;

Как и целая переменная, которой можно присвоить значение целого типа, процедурной переменной можно присвоить значение процедурного типа. Таким значением может быть, конечно, другая процедурная переменная, но оно может также представлять собой идентификатор процедуры или функции. В таком контексте описания процедуры или функции можно рассматривать, как описание особого рода константы, значением которой является процедура или функция. Например, пусть мы имеем следующие описания процедуры и функции:

procedure Swap(var A,B: integer);

var

Temp: integer;

begin

Temp := A;

A := B;

B := Temp;

end.

function Tan(Angle: real): real;

begin

Tan := Sin(Angle) / Cos(Angle);

end.

Описанным ранее переменным P и F теперь можно присвоить значения:

P := Swap;

F := Tan;

После такого присваивания обращение P(i,j) эквивалентно Swap (i,j) и F(X) эквивалентно Tan(X).

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

Кроме того, для обеспечения совместимости по присваиванию процедура и функция, если ее нужно присвоить процедурной переменной, должна удовлетворять следующим требованиям:

- Это не должна быть стандатная процедура или функция.

- Такая процедура или функция не может быть вложенной.

- Такая процедура не должна быть процедурой типа inline.

- Она не должна быть процедурой прерывания (interrupt).

Стандартными процедурами и функциями считаются процедуры и функции, описанные в модуле System, такие, как Writeln, Readln, Chr, Ord. Чтобы получить возможность использовать стандартную процедуру или функцию с процедурной переменной, вы должны написать для нее специальную "оболочку". Например, пусть мы имеем процедурный тип:

type

IntProc = procedure(N: integer);

Следующая процедура для записи целого числа будет совместимой по присваиванию:

procedure WriteInt(Number: Integer); far;

begin

Write(Number);

end.

Вложенные процедуры и функции с процедурными переменными использовать нельзя. Процедура или функция считается вложенной, когда она описывается внутри другой процедуры или функции. В следующем примере процедура Inner вложена в процедуру Outer и поэтому ее нельзя присваивать процедурной переменной:

program Nested;

procedure Outer;

procedure Inner;

begin

Writeln('Процедура Inner является вложенной');

end;

begin

Inner;

end;

begin

Outer;

end.

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

type

GotoProc = procedure(X,Y: integer);

ProcList = array[1..10] of GotoProc;

WindowPtr = ^WindowRec;

Window = record

Next: WindowPtr;

Header: string[31];

Top,Left,Bottom,Right: integer;

SetCursor: GotoProc;

end;

var

P: ProcList;

W: WindowPtr;

С учетом этих описаний допустимы следующие вызовы процедур:

P[3](1,1);

W.SetCursor(10,10);

Когда процедурной переменной присваивается значение процедуры, то на физическом уровне происходит следующее: адрес процедуры сохраняется в переменной. Фактически, процедурная переменная весьма напоминает переменную-указатель, только вместо ссылки на данные она указывает на процедуру или функцию. Как и указатель, процедурная переменная занимает 4 байта (два слова), в которых содержится адрес памяти. В первом слове хранится смещение, во втором - сегмент.

Параметры процедурного типа

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

program Tables;

type

Func = function(X,Y: integer): integer;

function Add(X,Y: integer): integer; far;

begin

Add := X + Y;

end;

function Multiply(X,Y: integer): integer; far;

begin

Multiply := X*Y;

end;

function Funny(X,Y: integer): integer; far;

begin

Funny := (X+Y) * (X-Y);

end;

procedure PrintTable(W,H: integer; Operation: Func);

var

X,Y : integer;

begin

for Y := 1 to H do

begin

for X := 1 to W do Write(Operation(X,Y):5);

Writeln;

end;

Writeln;

end;

begin

PrintTable(10,10,Add);

PrintTable(10,10,Multiply);

PrintTable(10,10,Funny);

end.

При работе программа Table выводит три таблицы. Вторая из них выглядит следующим образом:

1 2 3 4 5 6 7 8 9 10

2 4 6 8 10 12 14 16 18 20

3 6 9 12 15 18 21 24 27 30

4 8 12 16 20 24 28 32 36 40

5 10 15 20 25 30 35 40 45 50

6 12 18 24 30 36 42 48 54 60

7 14 21 28 35 42 49 56 63 70

8 16 24 32 40 48 56 64 72 80

9 18 27 36 45 54 63 72 81 90

10 20 30 40 50 60 70 80 90 100

Параметры процедурного типа особенно полезны в том случае, когда над множеством процедур или функций нужно выполнить какие-то общие действия. В данном случае процедуры PrintTable представляет собой общее действие, выполняемое над функциями Add, Multiply и Funny.

Если процедура или функция должны передаваться в качестве параметра, они должны удовлетворять тем же правилам совместимости типа, что и при присваивании. То есть, такие процедуры или функции должны компилироваться с директивой far, они не могут быть встроенными функциями, не могут быть вложенными и не могут описываться с атрибутами inline или interrupt.

Соседние файлы в папке tp3