Энциклопедия Turbo Pascal. Главы 9-11
Страница 27. Использование процедур и функций


Использование процедур и функций

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

    Версия 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 раз. Ес-
ли вы хотите написать быстрый код,  то использование данной функ-
ции внутри цикла - это не самый лучший подход.

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

 
Следующая статья »