Энциклопедия Turbo Pascal. Главы 9-11 - Использование процедур и функций
ОГЛАВЛЕНИЕ
Использование процедур и функций
Всегда помните, что использование процедур и функций с локальными переменными составляет основу структурного программирования. Процедуры и функции являются строительными блоками программ на Турбо Паскале и составляют самое главное положительное качество данного языка. Вам следует знать несколько особенностей функций Турбо Паскаля, которые влияют на размер и скорость выполнения вашего кода.
Во-первых, Турбо Паскаль является стеково-ориентированным языком: все локальные переменные и параметры используют стек для промежуточного запоминания. При вызове функции адрес возврата вызвавшей процедуры также помещается в стек. Это позволяет программе осуществить возврат в точку, из которой был вызов. Когда функция возвращает управление, данный адрес и все локальные переменные и параметры должны быть удалены из стека. Процесс заталкивания данной информации в стек называется последовательностью вызова, а процесс выталкивания информации из стека последовательностью возврата. Эти последовательности требуют определенного времени и иногда довольно большого.
Чтобы понять, как вызов функции может замедлить вашу программу, рассмотрим два примера:
Версия 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 раз. Если вы хотите написать быстрый код, то использование данной функции внутри цикла - это не самый лучший подход.
Теперь вы можете подумать, что следует писать программы, которые состоят из нескольких больших процедур и которые, следовательно, будут работать быстрее. В большинстве случаев, однако, небольшие различия во времени выполнения не важны, а вот потеря структуры будет ощутимой. Но это другая проблема. Замена вызовов подпрограмм, которые используются различными процедурами, на непосредстевнные коды сделает вашу программу очень большой, так как один и тот же код будет дублироваться большее количество раз. Помните, что подпрограммы были выдуманы главным образом как средство повышения эффективности использования памяти. Положение таково, что убыстрение программы ведет к ее увеличению, а уменьшение программы ведет к ее замедлению. Использовать непосредственный код вместо вызовов функций следует только тогда, когда скорость имеет абсолютный приоритет. В противном случае рекомендуется повсеместное применение процедур и функций.