Всегда помните, что использование процедур и функций с ло-
кальными переменными составляет основу структурного программиро-
вания. Процедуры и функции являются строительными блоками прог-
рамм на Турбо Паскале и составляют самое главное положительное
качество данного языка. Вам следует знать несколько особенностей
функций Турбо Паскаля, которые влияют на размер и скорость выпол-
нения вашего кода.
Во-первых, Турбо Паскаль является стеково-ориентированным
языком: все локальные переменные и параметры используют стек для
промежуточного запоминания. При вызове функции адрес возврата
вызвавшей процедуры также помещается в стек. Это позволяет прог-
рамме осуществить возврат в точку, из которой был вызов. Когда
функция возвращает управление, данный адрес и все локальные пере-
менные и параметры должны быть удалены из стека. Процесс заталки-
вания данной информации в стек называется последовательностью вы-
зова, а процесс выталкивания информации из стека -
последовательностью возврата. Эти последовательности требуют оп-
ределенного времени и иногда довольно большого.
Чтобы понять, как вызов функции может замедлить вашу прог-
рамму, рассмотрим два примера:
Версия 1 Версия 2
for x:=1 to 100 do for x:=1 to 100
t:=compute(x); t:=Abs(Sin(q)/100/3.1416);
function compute(q: integer): real;
var
t:real;
begin
compute:=Abs(Sin(q)/100/3.1416);
end;
Хотя каждый цикл выполняет одну и ту же функцию, версия 2
гораздо быстрее, так как использование непосредственного кода
устраняет задержки, связанные с последовательностями вызова и
возврата. Для понимания того, сколько времени тратится, рассмот-
рим следующий код на псевдоассемблере, который демонстрирует в
теории последовательности вызова и возврата для функции compute:
; последовательность вызова
move A, x ; поместить значение х в аккумулятор
push A
call compute ; инструкция вызова помещает адрес
; возврата в стек
; последовательность возврата
; значение возврата функции должно быть помещено в
; регистр - мы используем В
move B, stack-1 ; доставить значение во временное t
return ; возврат к вызвавшей процедуре
; вызвавшая процедура затем выполняет следующие действия
Использование функции compute внутри цикла ведет к тому, что
последовательности вызова и возврата будут выполнены 100 раз. Ес-
ли вы хотите написать быстрый код, то использование данной функ-
ции внутри цикла - это не самый лучший подход.
Теперь вы можете подумать, что следует писать программы, ко-
торые состоят из нескольких больших процедур и которые, следова-
тельно, будут работать быстрее. В большинстве случаев, однако,
небольшие различия во времени выполнения не важны, а вот потеря
структуры будет ощутимой. Но это другая проблема. Замена вызовов
подпрограмм, которые используются различными процедурами, на не-
посредстевнные коды сделает вашу программу очень большой, так как
один и тот же код будет дублироваться большее количество раз.
Помните, что подпрограммы были выдуманы главным образом как
средство повышения эффективности использования памяти. Положение
таково, что убыстрение программы ведет к ее увеличению, а умень-
шение программы ведет к ее замедлению. Использовать непосредс-
твенный код вместо вызовов функций следует только тогда, когда
скорость имеет абсолютный приоритет. В противном случае рекомен-
дуется повсеместное применение процедур и функций.