Ada (798525), страница 13
Текст из файла (страница 13)
Однако теперь, если будет изменена тольковнутренняя подпрограмма, то только она должна быть подвергнута перекомпиляциикомпилятором. Это также позволяет разделить программу на несколько частей, что можетоблегчить ее понимание.6.1.6 Подпрограммы как библиотечные модулиЛюбая подпрограмма Ады, при необходимости, может быть оформлена как абсолютносамостоятельный независимый библиотечный подпрограммный модуль.Рассмотрим как это делается на примере процедур Ive_Got_A_Procedure иDisplay_Values, из предыдущего примера о раздельной компиляции. Теперь, процедураDisplay_Values будет оформлена как самостоятельный библиотечный подпрограммныймодуль, а процедура Ive_Got_A_Procedure будет ее использовать.В этом случае, полное описание процедуры Display_Values будет состоять из двух файлов:файла спецификации и файла тела процедуры.Примечание:В системе компилятора GNAT существует соглашение согласно которому файлыспецификаций имеют расширение ads (ADa Specification), а файлы тел имеютрасширение adb (ADa Body).Файл спецификации процедуры Display_Values (display_values.ads) будет иметьследующий вид:procedure Display_Values(Number : Integer);Файл тела процедуры Display_Values (display_values.adb) будет иметь следующийвид:with Ada.Text_IO;use Ada.Text_IO;with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;procedure Display_Values(Number : Integer) isbeginPut(Number);New_Line;end Display_Values;ТретийфайлэтофайлтелапроцедурыIve_Got_A_Procedure(ive_got_a_procedure.adb).
В этом случае он будет иметь следующий вид:with Ada.Text_IO;use Ada.Text_IO;with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;with Display_Values;procedure Ive_Got_A_Procedure isX : Integer := 6;Y : Integer := 5;beginDisplay_Values(X);Display_Values(Y);end Ive_Got_A_Procedure;Примечательно, что теперь, в файле тела процедуры Ive_Got_A_Procedure, процедуруDisplay_Values, которая оформлена как самостоятельный библиотечный модуль,необходимо указать в спецификаторе совместности контекста with.Также, необходимо заметить, что подпрограммы, оформленные как самостоятельныебиблиотечные модули, не указываются в спецификаторе использования контекста use.6.2 Режимы передачи параметровСтандарт Ada83 предусматривал три режима передачи параметров для подпрограмм:"in""in out""out"Стандарт Ada95 добавил еще один режим передачи параметров:accessВсе эти режимы не имеют непосредственных аналогов в других языках программирования.Необходимо также отметить следующее:по-умолчанию, для передачи параметров подпрограммы, всегда устанавливается режим "in" !!!Для "in" / "out" скалярных значений используется механизм передачи параметров покопированию-"in" (copy-in), по копированию-"out" (copy-out).
Стандарт специфицирует, чтолюбые другие типы могут быть переданы по copy-in/copy-out, или по ссылке.Ada95 указывает, что лимитированные приватные типы (limited private types), которыерассматриваются позднее, передаются по ссылке, для предотвращения проблем нарушенияприватности.6.2.1 Режим "in"Параметры передаваемые в этом режиме подобны параметрам передаваемым по значению вязыке Паскаль, и обычным параметрам языка Си, с тем исключением, что им не могутприсваиваться значания внутри подпрограммы.Это значит, что при входе в подпрограмму, формальный параметр инициализируется значениемфактического параметра, при этом, внутри подпрограммы, он является константой и разрешаеттолько чтение значения ассоциированного фактического параметра.with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;procedure Demo(X : in Integer; Y : in Integer) isbeginX := 5; -- недопустимо, in параметр доступен только по чтениюPut(Y);Get(Y); -- также недопустимоend Demo;Режим "in" разрешается использовать и в процедурах, и в функциях.6.2.2 Режим "in out"Этот режим непосредственно соответствует параметрам передаваемым по ссылке (подобно varпараметрам языка Паскаль).Таким образом, при входе в подпрограмму, формальный параметр инициализируется значениемфактического параметра.
Внутри подпрограммы, формальный параметр, использующий этотрежим, может быть использован как в левой, так и в правой части инструкций присваивания(другими словами: формальный параметр доступен как для чтения, так и для записи). При этом,если формальному параметру внутри подпрограммы произведено присваивание новогозначения, то после выхода из подпрограммы значение фактического параметра заменяется нановое значение формального параметра.procedure Demo(X : in out Integer;Y : inInteger) isZ : constant Integer := X;beginX := Y * Z; -- это допустимо!end Demo;Режим "in out" разрешается использовать только в процедурах.6.2.3 Режим "out"В этом режиме, при входе в подпрограмму, формальный параметр не инициализируется (!!!)значением фактического параметра.
Согласно стандарта Ada95, внутри подпрограммы,формальный параметр, использующий этот режим, может быть использован как в левой, так и вправой части инструкций присваивания (другими словами: формальный параметр доступен какдля чтения, так и для записи). Согласно стандарта Ada83, внутри подпрограммы, такойформальный параметр может быть использован только в левой части инструкций присваивания(другими словами: доступен только для записи).
При этом, после выхода из подпрограммы,значение фактического параметра заменяется на значение формального параметра.procedure Demo(X : out Integer;Y : in Integer) is-- при входе в подпрограмму X не инициализирован!!!beginX := Y;end Demo;Режим "out" разрешается использовать только в процедурах.6.2.4 Режим accessПоскольку значения ссылочного типа (указатели) часто используются в качестве параметровпередаваемых подпрограммам, Ада предусматривает режим передачи параметров access,который специально предназначен для передачи параметров ссылочного типа.
Заметим, чтоподробному обсуждению ссылочных типов Ады далее посвящена самостоятельная глава "Ссылочные типы (указатели)". Необходимо также обратить внимание на то, что режимпередачи параметров access был введен стандартом Ada95 и он отсутствует в стандарте Ada83.При использовании режима access, фактический параметр, который предоставляется привызове подпрограммы, - это любое значение ссылочного типа, которое ссылается (указывает) наобъект соответствующего типа. При входе в подпрограмму, формальный параметринициализируется значением фактического параметра, при этом, Ада производитавтоматическую проверку того, что значение параметра не равно null. В случае когда значениепараметра равно null генерируется исключительная ситуация Constraint_Error (проще говоря, ошибка).
Внутри подпрограммы, формальный параметр, использующий режим access,является константой ссылочного типа и ему нельзя присваивать новое значение, поэтому такиеформальные параметры несколько подобны формальным параметрам, использующим режим"in". Однако, поскольку параметр является значением ссылочного типа (указателем), топодпрограмма может изменить содержимое объекта на который данный параметр ссылается(указывает). Кроме того, внутри подпрограммы такой параметр принадлежит анонимномуссылочному типу, и поскольку у нас нет возможности определить имя этого ссылочного типа, томы не можем описать ни одного дополнительного объекта этого типа.
Любая попыткаконвертирования значения такого параметра в значение именованого ссылочного типа будетпроверяться на соответствие правилам области действия для ссылочных типов. Приобнаружении нарушения этих правил генерируется исключительная ситуация Programm_Error....function Demo_Access(A : access Integer) return Integer isbeginreturn A.all;end Demo_Access;...typeInteger_Accessis access Integer;Integer_Access_Var : Integer_Access := new Integer'(1);Aliased_Integer_Var : aliased Integer;...X : Integer := Demo_Access(Integer_Access_Var);Y : Integer := Demo_Access(Aliased_Integer_Var'Access);Z : Integer := Demo_Access(new Integer);.
. .Режим access разрешается использовать и в процедурах, и в функциях.При этом необходимо обратить внимание на то, что функции, использующие этот режим дляпередачи параметров, способны изменять состояние объектов на которые такие параметрыссылаются. То есть, такие функции могут обладать побочными эффектами.6.3 Сопоставление формальных и фактических параметров6.3.1 Позиционное сопоставлениеПозиционное сопоставление формальных и фактических параметров при вызове подпрограммыдостаточно традиционно, и используется во многих языках программирования. При такомсопоставлении, ассоциирование между формальными и фактическими параметрамипроизводится один к одному позиционно, т.е.