понедельник, 11 апреля 2011 г.

Вызов процедур и функций

Перевод из справочной системы Delphi

Управление и параметры

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


При вызове подпрограммы следует помнить следующее:
  • Выражения, использованные при передаче типизированных параметров-констант, должны быть совместимы по присваиванию с соответствующими формальными параметрами.
  • Тип выражений, использованных при передаче параметров var и out, должен быть идентичен типам соответствующих формальных параметров (кроме тех случаев, когда формальные параметры нетипизированы).
  • Только выражения, для которых возможно присваивание, могут быть переданы в качестве параметров var и out.
  • Если формальные параметры подпрограммы нетипизированы, числа и действительные константы (true constants) с числовыми значениями не могут быть использованы как действительные параметры.
  • При вызове подпрограммы с параметрами, для которых указаны значения по умолчанию, все действительные параметры, следующие за первым значением по умолчанию, должны также иметь значения по умолчанию (вызовы вида SomeFunction(,,X) не допускаются).


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

procedure DoSomething
(X: Real = 1.0; I: Integer = 0; S: string = );
следующие вызовы эквивалентны:
DoSomething();
DoSomething;

Конструкторы открытых массивов

Конструкторы открытых массивов позволяют создавать массивы непосредственно при вызове процедуры или функции. Они могут быть переданы только как параметры-открытые массивы или параметры-вариантные открытые массивы.

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

var I, J: Integer;
procedure Add(A: array of Integer);
вы сможете вызывать процедуру Add при помощи инструкции:
Add([5, 7, I, I + J]);
Что эквивалентно:
var Temp: array[0..3] of Integer;
    ...
  Temp[0] := 5;
  Temp[1] := 7;
  Temp[2] := I;
  Temp[3] := I + J;
  Add(Temp);

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

Применение директивы inline

Компилятор Delphi позволяет для улучшения производительности помечать функции и процедуры директивой встраивания inline. Если функция или процедура удовлетворяет определенным критериям, компилятор будет при вызове подпрограммы вставлять ее код в текущий блок, не генерируя ее вызов. Встраивание – это оптимизация, которая может создавать более быстрый код в ущерб расходованию ресурсов. Встраивание во всех случаях заставляет компилятор производить больший двоичный файл. Директива inline применяется при объявлении функций и процедур и прочих объявлениях по тем же правилам, что и остальные директивы.

procedure MyProc(x:Integer); inline;
begin
    // ...
end;

function MyFunc(y:Char) : String; inline;
begin
   // ..
end;

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

  • Встраивание не будет выполнено в любых методах с поздней линковкой. Это касается виртуальных, динамических методах и методах-сообщениях.
  • Подпрограммы, содержащие код на ассемблере, не могут быть встроены.
  • Конструкторы и деструкторы не могут быть встроены.
  • Блок основной программы, секции инициализации или финализации модулей не могут быть встроенными.
  • Подпрограммы, которые не определены на момент использования, не могут быть встроены.
  • Подпрограммы, принимающие в качестве параметров открытые массивы, не могут быть встроены.
  • Код может быть встроен внутри пакетов, но встраивание никогда не выходит за границы пакета.
  • Встраивание не может быть выполнено между модулями, которые зависимы друг от друга. Это касается и непрямой циклической зависимости. Например, если модуль А подключает модуль В, а модуль В подключает модуль С, который в свою очередь подключает модуль А, то при компиляции модуля А, код из модулей В и С не может быть встроен в модуль А.
  • При наличии циклической зависимости компилятор может встроить код в том случае, когда встраиваемый код поступает в модуль из модуля, не вовлеченного в эту циклическую зависимость. В приведенном выше примере, если модуль А также подключает и модуль D, то, поскольку модуль D не вовлечен в циклическую зависимость, код из него может быть встроен в А.
  • Если подпрограмма объявлена в секции interface и выполняет доступ к идентификаторам в секции implementation, она не может быть встроена.
  • Если подпрограмма, помеченная как inline использует внешние идентификаторы из других модулей, все эти модули должны быть перечислены в разделе подключения модулей, в противном случае, встраивания подпрограммы не произойдет.
  • Процедуры и функции, которые используются в выражениях условий в инструкциях while-do и repeat-until, не могут быть встроены.
  • В модуле, тело встраиваемой функции должно быть определено до того как будут выполнены вызовы этой функции. То есть тело функции не может быть встроено, если оно неизвестно компилятору на момент обработки вызова функции.

Если вы изменяете реализацию встроенной функции, вы заставляете компилятор перекомпилировать все модули, использующие эту функцию. Это правило отличается от обычных правил перекомпиляции, определяющих, что перекомпиляция запускается только в том случае, если изменения произведены в секции interface.

Директива компилятора {$INLINE} предоставляет дополнительные возможности для управления встраиванием. Директива {$INLINE} может быть использована при объявлении подпрограммы или при ее вызове.

Ниже приведены возможные значения директивы и их смысл:
ЗначениеЗначение при определенииЗначение в месте вызова
{$INLINE ON} (по умолчанию)Подпрограмма компилируется как встраиваемая, в том случае, если она помечена как inline.Подпрограмма будет встроена, если это возможно.
{$INLINE AUTO}Действует как {$INLINE ON}, при этом встраиваются также и подпрограммы не помеченные директивой inline, в том случае, если размер их кода не привышает 32 байт{$INLINE AUTO} не действует в том случае, если она используется в месте вызова подпрограммы.
{$INLINE OFF}Подпрограмма не будет помечана как встраиваемая даже при использовании ключевого слова inline.Подпрограмма не будет встроена.

3 комментария:

  1. Начиная с какой версии Delphi позволяет создавать inline-функции?

    ОтветитьУдалить
  2. хммм...
    У меня в Delphi Rio при указании Inline функции просто перестают работать.
    Под отладчиком туда не заходит, а результат абсолютно не корректный.

    ОтветитьУдалить