Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 117
Текст из файла (страница 117)
Но это на самом деле противоречит олному из принципов разработки языков программирования: программист нс должен беспокоиться о деталях реализации языка. В языке Аг!а, например, используется другой подход. Вместо того чтобы явно указывать способ перелачн, програмьшст должен только определить поль данного параметра. 9.3. Передача параметров 423 Параметр может быть определен с помоьцью ключевого слова 1п как входной параметр, что означает передачу значения фактического параметра формальному параметру с последующим его использованием в подпрограмме. Параметр может быть определен с помощью ключевого слова ощ как выходной параметр, значение которого генерируется в вызванной подпрограмме и затем передается назад фактическому параметру при выходе из подпрограммы, И наконец, параметр может быть определен с помощью ключевых слов 1п оцг одновременно как входной и выходной.
В этом случае его значение передается в вызванную подпрограмму, а затем значение результата передается обратно фактическому параметру. Язык Лс1а определен таким образом, что при его реализации для некоторых из перечисленных типов параметров можно выбрать альтернативные методы их передачи. Для программиста выбор того или иного метода реализации не оказывает влияния на конечный результат, если только вызваш шя программа нормально завершается и не имеет доступа к фактическим параметрам через псевдонимы. В исходном определении языка Ас1а (Ада 83) разработчик имел возможность выбора между передачей по ссылке и передачей по значешпо для реализации входных (1п) и выходных (опт) параметров.
Это приводило к проблемам согласования, так как правильные программы могли давать различные результаты при компиляции с помощью различных правильных компиляторов. Поэтому в пересмотренном варианте языка Аг(а 95 подход к передаче параметров был пересмотрен. + Элементарные типы данных (например, скалярные величины типа целых чисел, вещественных чисел или булевых значений) передаются по значениюконстапте, если они являются входными (1п) параметрами, и по значению- результату, если являются выходными (опт) или одновременно входными и выхолными (1п опт) параметрами.
+ Составные типы донных (например, массивы и записи) передаются по ссылке. Эти нововведения упростили передачу параметров в Лг(а, но все жс некоторая возможность путаницы при выполнении подпрограмм остается (см. задачу 23 в конце этой главы). Явные значения функций В большинстве языков, если результатом подпрограммы является только одно значение, его можно возвратить как явное значение функции, а не через параметр. В этом случае подпрограмма должна быть объявлена как подпрограмма-функция, а тип возвращаемого результата должен быть задан в спецификации этой подпрограммы, как, например, в объявлении С П са1 Гп(1п1 з1, которос определяет 1п как подпрограмму-функцию, возвраьца|ощую результат вещественного типа.
В теле подпрограммы-функции результат, возвращаемый как значение функции, может быть определен одним из двух способов. В первом способе, используемом в языке С, возвращаемое значение функции следует задать в виде явного выражения в операторе гетцгп, который завершает выл юлпение подпрограммы (например, гетцгп 2 * х для указания того, что значение выражения 2 * х должно быть возврагцено как результат выполнения подпрограммы-функции). В Разса1 используется альтернативный спосоо: возвра1цасмое значение присваивается имени функции внутри 424 Глава 9.
Управление подпрограммами подпрограммы-функции (например, Тп:= 2 * х). В этом способе подпрограмма может содержать несколько операторов присваивания значения имени функции. При этом в вызывающую подпрограмму возвращается последнее из присвоенных перед завершением подпрограммы значений. В обоих способах, возможно, было бы лучше рассматривать возвращаемое значение как дополнительный неявный выходной (ощ) параметр подпрограммы.
9.3.4. Реализация передачи параметров Поскольку каждая активация подпрограммы получает разный набор значений параметров, память под формальные параметры подпрограммы обычно выделяется в записи активации подпрограммы, а не в сегменте кода. Каждый формальный параметр является в подпрограмме локальным объектом данных. Если в заголовке подпрограммы указано, что формальный параметр Р принадлежит некоторому типу Т (то есть фактический параметр, соответствующий данному формальному, является объектом данных типа Т), то формальный параметр реализуется одним из двух способов, в зависимости от используемого способа передачи (как обсуждалось выше).
Формальный параметр Р рассматривается либо как локальн ый объект данных типа Т (начальное значение которого может быть копией значения фактического параметра), либо как локальный объект данных типа указатель на объект данных типа Т (начальным значением которого является указатель на объект данных, соответствующий фактическому параметру).
Первый из этих двух методов используется для передачи параметров по значению-результату, по значению и по результату; второй используется для передачи параметров по ссылке. Любой из этих методов можно использовать для реализации передачи параметров по значению-константе. Явное значение функции можно трактовать как передачу параметра с помощью первого из описанных методов. Если в определении языка не предусмотрена спецификация типов лля формальных параметров (как, например, в 118Р, АР1. и Вй(ОВОЕ4), то формальный параметр может быть реализован квк локальная переменная-указатель, но хранящийся в ней указатель может указывать па объект данных произвольного тина. Различные действия, связанные с передачей параметров, можно разбить на две группы: тс, которые связаны с точкой вызова подпрограммы в каждой вызывающей подпрограмме, и тс, которые связаны с входом и выходом пз подпрограммы.
В точке вызова в каждой вызывающей подпрограмме вычисляется каждое выражение фактического параметра и создается список указателей (а иногда — просто копии их значений) на обьекты данных, соответствуклцие фактическим параметрам. Важно понимать, что это вычисление происходит в точке вызова, в среде ссылок вызывающей подпрограммы. Когда фактические параметры определены, управление передается вызываемой подпрограмме. Обычно это влечет за собой изменения в значениях указателей СГР и С1Р (как описано в главе 8).
что приводит к передаче управления на начало выполняемого кода вызванной подпрограммы и также изменению среды ссылок на среду соответствующей вызванной подпрограммы. После передачи управления подпрограмме в ее прологе завершаются действия, связанные с передачей параметров, — в формальный параметр копируется либо 9.3. Передача параметров 425 значение фактического параметра, либо указатель на фактический параметр.
Перед завершением подпрограммы ее эпилог лолжен скопировать возвращаемые результаты в фактические параметры, переданные по результату или по значению- результату. Значения функций также должны быть скопированы в регистры или во временную память, предоставленную вызывающей подпрограммой. Затем подпрограмма заканчивается и ее запись активации уничтожается, так что обычно все результаты должны быть скопированы из записи активации еще ло завершения подпрограммы.
При реализации передачи параметров компилятор выполняет две основные задачи. Сначала он должен сгенерировать правильный выполняемый код для передачии параметров, возвращения результатов и для всех ссылок на имена формальных параметров. Поскольку в большинстве языков предусмотрено несколько методов передачи параметров, необходимый в каждом случае выполняемый кол часто слегка различается. Генерация этого кода также является непростой задачей, поскольку затрагивает координацию действий, выполняемых в кажлой точке вызова подпрограммы, в ее прологе и эпилоге. Второй важной задачей компилятора является выполнение необходимой статической проверки типов для гарантии того, что тип кажлого об ьекта данных, соответствующего фактическому параметру, совпадает с типом, объявленным для соответствующего формального параметра.
Пля выполнения этой проверки компилятор должен знать спецификацию вызываемой подпрограммы (количество, порядок и типы параметров), а внутренняя структура тела подпрограммы не имеет значения. Эта спецификация должна быть доступна компилятору в лк>бой точке вызова подпрограммы. Во многих языках, особенно в тех, в которых допускается раздельная компиляция подпрограмм, если подпрограмма 0 вызывается из подпрограммы Р, то при компиляции Р должна быть предоставлена отдельная спецификация О, даже если определение подпрограммы 0 находится в каком-либо другом месте. Это необходимо для того, чтобы компилятор мог выполнить статическую проверку типов и сгенерировать соответствующий код для передачи параметров в каждой точке вызова.
Примеры передачи параметров Комбинация методов передачи параметров с различными типами фактических параметров приводит к разнообразным эффектам. Некоторые примеры использованы для объяснения различных тонкостей передачи параметров. В приведенных примерах используются два метода передачи параметров: по ссылке и но значению. Отличия, возникающие при использовании других методов, рассматриваются в задачах в конце главы. Все примеры написаны на языке С. В нашей версии С нмя формального параметра с предшествующим символом «звездочка» (*) передается по ссылке, а прн ее отсутствии — по зпа <ению. Простые переменные и константы.
В листинге 9.7 (а) привелена подпрограмма 0 на языке С с двумя формальными параметрами; ц передаваемым по значению, и1, передаваемым по ссылке. Предположим, что мы написали подпрограмму Р, вызывающую эту подпрограмму 0 с двумя целочисленными переменными а и Ь в качестве фактических параметров (лпстиш 9.7, б). При выполнении подпрограммы Р два оператора печати выведут следующие числа: 12 13 2 13. Проследим за каждым из параметров по очереди.