Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
327582.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
392 Кб
Скачать
☆

24,Внешние подпрограммы.

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

Заголовок_подпрограммы

[операторы_описания]

[исполняемые_операторы]

[CONTAINS

внутренние_подпрограммы]

END [спецификатор_подпрограммы [ имя__подпрограммы] ]

Здесь Заголовок_подпрограммы имеет вид:

{префикс__спецификатора] спецификатор_подлрограммы имя_подпрограммы

[(список_формальных_параметров)]

где спецификатор_подпрограммы — один из операторов: subroutine или

function; имя_подпрограммы — уникальное имя, удовлетворяющее правилам

фортрана, за которым может следовать необязательный список_формальных_

параметров, заключенный в круглые скобки. Спецификатор подпрограммы

указывает, является ли подпрограмма процедурой или функцией. Процедура

не имеет возвращаемого значения: результаты ее работы передаются либо

через формальные параметры, либо через глобальные переменные. Функция

же возвращает значение заданного типа, которое может быть присвоено пе-

ременной или подставлено в выражение. Поэтому префикс_спецификатора

для функций содержит тип возвращаемого значения. Обращение к процедуре осуществляется оператором call, имеющим вид:

CALL имя_подпрограммы [(список_фактических_параметров)],

например,

CALL BIGSUB

Вызов функции не требует никакого специального оператора:

REAL A, X

REAL, EXTERNAL :: MYFUNC

А = MYFUNC (X)

Оператор end подпрограммы возвращает управление тому программному компоненту, из которого подпрограмма была вызвана. Есть способ сделать это, не дожидаясь конца подпрограммы — оператор return прекратит выполнение подпрограммы в любом ее месте и передаст управление в место вызова. Как и оператор stop, он может иметь метку и быть частью условного оператора. Оператор return не может появляться в главной программе и в подпрограммах-функциях. Если в операторе end указано имя подпрограммы или функции, оно должно совпадать с именем, указанным в заголовке. Пример главной программы с внешней подпрограммой: Пример главной программы с внешней подпрограммой

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

DATA X, Y /0.755545, 6.873452/

CALL outer_sub(X, Y, S)

158 Глава 7

WRITE(*, *) 'Result of outer_sub S =', S

END PROGRAM main

SUBROUTINE outer_sub(A, В, С)

REAL А, В, С

С = SQRT(A**2 + B**2)

END SUBROUTINE outer_sub

1)Внешнии подпрграммы:

program swapab

Integer::a,b

a=5

b=1

call swap(A,b)

print*,'A=',a,'B=',b

end program

subroutine swap(c,d)

Integer::d,c,tmp

tmp=d

d=c

c=tmp

end subroutine

Внутренние подпрограммы

Внутренние подпрограммы, в отличие от внешних, не могут содержать собственных внутренних подпрограмм и имеют вид:

Заголовок_подпрограммы

[операторы_описания]

[исполняемые_операторы]

END [спецификатор_подпрограммы [имя_подпрограммы]]

Внутренняя подпрограмма автоматически получает доступ ко всем объектам своего носителя, в том числе, к другим внутренним подпрограммам Все обращения к внутренним подпрограммам могут производиться только из компонента-носителя Пример внутренней подпрограммы в главной программе:

Пример главной программы с внутренней подпрограммой:

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

DATA X, Y /0.755545, 6.873452/

CALL inner_sub(X, Y, S)

WRITE(*, *) 'Result of inner_sub S =', S

CONTAINS

SUBROUTINE inner_Sub(A, В, С)

REAL А, В, С

С = SQRT(A**2 + B**2)

END SUBROUTINE inner_sub

END PROGRAM inam

Программа, состоящая из двух компонент с внутренними подпрограммами, имена которых совпадают. Тем не менее, каждый компонент уверенно вызывает только свою подпрограмму

Внутренние подпрограммы:

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

DATA X, Y /0 755545, 6.873452/

CALL inner_sub(X, Y, S)

WRITE(*, *) 'Result of main1's inner_sub S =', S

CALL outer_sub(X, Y, S)

WRITE(*, *) 'Result of outer_sub S =', S

CONTAINS

SUBROUTINE inner_sub(A, В, С)

REAL, PARAMETER :: R = 5.,RR = SQRTE / 2.0)

REAL А, В, С

С = SQRT(A**2 + B**2)

IF (C > R) THEN

IF (A > RR) A = RR

IF(B > RR) В = RR

END IF

END SUBROUTINE inner_sub

END PROGRAM main

SUBROUTINE outer_sub(A, В, С)

REAL А, В, С

REAL S

CALL inner_sub(A, B, S)

WRITE(*, *) 'Result of outer1's inner_sub S =', S

С = SQRT(A**2 + B**2)

CONTAINS

SUBROUTINE inner_sub(A, В, С)

REAL А, В, С

С = SQRT(ABS(A**2 - B**2))

END SUBROUTINE inner_sub

END SUBROUTINE outer_sub

Внутренние подпрограммы:

program swapab

Integer::a,b

a=5

b=1

call swap(A,b)

print*,'A=',a,'B=',b

contains

subroutine swap(c,d)

Integer::d,c,tmp

tmp=d

d=c

c=tmp

end subroutine

end program

МОДУЛИ:

MODULE имя_модуля

[операторы_описания]

[CONTAINS

модуль ные_подпрограммы ]

END [MODULE [имя_модуля]]

MODULE ARRAY

REAL, DIMENSIONB0) :: A

CONTAINS

….

END MODULE ARRAY,

Интерфейсы

Для организации вызова любой подпрограммы необходимо и достаточно

знать ее интерфейс: заголовок, список формальных параметров и их описа-

ния. Интерфейс внутренней подпрограммы всегда известен в области ее

использования: компонент-носитель знает все о параметрах внутренней

подпрограммы; другим же программным компонентам внутренние подпро-

граммы недоступны. Интерфейс внутренней подпрограммы представляет

образец явного интерфейса: проверить корректность обращения к ней можно

еще на стадии компиляции. Другим примером явного интерфейса являются

модульные подпрограммы и встроенные функции.

Внешняя подпрограмма и формальная процедура, как правило, не обладают явным интерфейсом. У компилятора нет сведений о параметрах внешних и формальных

процедур, т. е. их интерфейс является неявным. Поэтому на этапе компиля-

ции невозможно, например, выполнить проверку на соответствие межд>

фактическими и формальными параметрами.

Сделать неявный интерфейс явным можно, описав его в интерфейсном блоке

INTERFACE

заголовок_лодпрограммы

описание_формальных_параметров

[описание_локаль ных_переменных]

оператор_Е№Э_подпро граммы

END INTERFACE

В интерфейсный блок нельзя включать операторы data и format Имена

формальных параметров и порядок операторов описания можно, а в некото-

рых случаях, и нужно, менять. В интерфейсном блоке можно поместить

описание интерфейса программы, написанной на другом языке программи-

рования, например, на языке ассемблера или на языке С.

Интерфейсный блок размещается среди операторов описания; после этого

интерфейс подпрограммы, содержащейся в нем, становится явным.

В листинге 1. интерфейс внешней подпрограммы сделан явным посредст-

вом включения интерфейсного блока в главную программу.

Листинг 1. Интерфейсный блок

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

INTERFACE

SUBROUTINE outer_sub(A, В, С)

REAL А, В, С

END SUBROUTINE OUter_sub

END INTERFACE

DATA X, Y /0.755545, 6.873452/

CALL inner_sub(X, Y, S)

WRITE(*, *) 'Result of main''s inner_sub S =', S

CALL outer_sub(X, Y, S)

WRITE(*, *) 'Result of outer_sub S =', S

CONTAINS

SUBROUTINE inner_sub(A, В, С)

REAL, PARAMETER :: R = 5., RR = SQRTE. / 2.0)

REAL А, В, С

REAL, INTENT(OUT) :: С

С = SQRT(A**2 + B**2)

IF (C > R) THEN

IF (A > RR) A = RR

IF(B > RR) В = RR

END IF

END SUBROUTINE mner_sub

END PROGRAM main

25. Параметры подпрограмм

Все подпрограммы — и процедуры, и функции, — должны иметь возмож-

ность обмениваться данными с теми компонентами программы, из которых

они были вызваны. Подпрограммы получают входные данные от вызываю-

щего компонента и передают ему выходные данные — результаты своей

работы. Обмен информацией с подпрограммами может происходить через

параметры подпрограмм и/или через глобальные данные. Глобальные дан-

ные — это переменные, доступные в равной степени и подпрограмме, и вы-

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

в разделе "Модули" настоящей главы. Другой способ обмена информаци-

ей — передача данных через параметры подпрограмм. В этом случае в описа-

нии подпрограммы указывается список_формальных_параметров — перечень

переменных (среди них могут быть и имена функций), которые так или

иначе будут использоваться в ходе выполнения подпрограммы. Формальные

параметры должны быть (явно или неявно) описаны в операторах описания

подпрограммы. При вызове подпрограммы происходит подстановка факти-

ческих параметров на место формальных (листинг 1).

Листинг 1. Формальные и фактические параметры

SUBROUTINE sub(A, В, С) 'А, В, С - формальные параметры

REAL А, В, С

С = SQRT(A**2 + В**2)

END SUBROUTINE sub

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

DATA X, Y /0.755545, 6.873452/

CALL sub(X, Y, S) ' X, Y, S - фактические параметры

WRITE(*, *) 'Result of sub S =', S

END PROGRAM mam

Ограничения, накладываемые

на фактические параметры .

Фактические параметры обязаны согласовываться с соответствующими

формальными параметрами по типу, параметрам типа и по форме. Совпаде-

ния имен параметров не требуется. Более того, на место формального пара-

метра может быть подставлено выражение, тип и разновидность типа кото-

рого совпадают с типом и разновидностью формального параметра

Предполагается, что формальные параметры являются отдельными объекта-

ми, не совпадающими ни с какими другими объектами подпрограммы

Компилятор может скопировать входной параметр во внутреннюю перемен-

ную при входе в подпрограмму с тем, чтобы на выходе из нее вернуть со-

храненное значение фактическому параметру Поэтому на фактические па-

раметры накладываются следующие ограничения:

- любые действия, влияющие на фактический параметр в обход формаль-

ного параметра, запрещены;

- если хотя бы часть фактического параметра получает значение через

формальный параметр, то ссылаться на этот фактический параметр мож-

но только через формальный параметр.

То есть если в подпрограмме введен формальный параметр а, то в рамках

подпрограммы он будет доступен только как а, независимо от того, какой

фактический параметр подставляется на его место Возможность доступа

к фактическому параметру в обход формального появляется, например, то-

гда, когда фактическим параметром становится глобальная переменная из

присоединенного модуля или переменная, доступная через соммоы-блок.

26. Параметры подпрограмм

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

работы. Обмен информацией с подпрограммами может происходить через параметры подпрограмм и/или через глобальные данные. Глобальные данные — это переменные, доступные в равной степени и подпрограмме, и вы-

зывающему компоненту. Организация глобальных данных будет рассмотрена в разделе "Модули" настоящей главы. Другой способ обмена информацией — передача данных через параметры подпрограмм. В этом случае в описа-

нии подпрограммы указывается список_формальных_параметров — перечень переменных (среди них могут быть и имена функций), которые так или

иначе будут использоваться в ходе выполнения подпрограммы. Формальные

параметры должны быть (явно или неявно) описаны в операторах описания

подпрограммы. При вызове подпрограммы происходит подстановка факти-

ческих параметров на место формальных (листинг 1).

Листинг 1. Формальные и фактические параметры

SUBROUTINE sub(A, В, С) 'А, В, С - формальные параметры

REAL А, В, С

С = SQRT(A**2 + В**2)

END SUBROUTINE sub

PROGRAM main

IMPLICIT NONE

REAL X, Y, S

DATA X, Y /0.755545, 6.873452/

CALL sub(X, Y, S) ' X, Y, S - фактические параметры

WRITE(*, *) 'Result of sub S =', S

END PROGRAM mam

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

Категории формальных параметров

Параметры-значения (в списке формальных параметров не имеют атрибута). Передаются ПП через стек, как копии, и не изменяются ею.

Параметры-переменные (в списке формальных параметров имеют атрибут var). Передаются ПП через адреса, и могут изменяться ею. Используются для возврата результатов в вызывающую программу.

Выходные параметры-переменные (в списке формальных параметров имеют атрибут out). Подобны параметрам-переменным, но передаются только из ПП в программу.

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

Процедуры или функции. Это параметры процедурного типа. Задаются именами.

Параметры без типа. За правильность использования отвечает программист.

Умалчиваемые параметры. Их в списке фактических параметров можно пропускать. В списке формальных параметров для них нужно задать тип и значение.

27. Модули

Если целью внутренних и внешних подпрограмм является выполнение действий, определяемых подзадачей в рамках всей программы (внешние подпро-

граммы) или данного программного компонента (внутренние подпрограммы),

то задачей модуля является аккумуляция данных.

Структура модуля такова:

MODULE имя_модуля

[операторы_описания]

[CONTAINS

модуль ные_подпрограммы ]

END [MODULE [имя_модуля]]

Модуль включается в другие программные компоненты оператором use. Все объекты модуля, не имеющие атрибута private, могут использоваться во

включающих компонентах.

Оператор use имеет возможность ограничить доступ к частям модуля или переименовать объекты, доступ к которым разрешен. (Подробнее об опера-

торе use будет рассказано в одном из следующих разделов.) Если ограничений не установлено, все объекты модуля доступны, модульныеподпрограммы

имеют структуру внешних подпрограмм, за исключением того, что оператор end, завершающий их описание, обязан содержать слово subroutine или

function в соответствии с видом подпрограммы. Все объекты модуля автоматически доступны для модульных подпрограмм.

Модули можно вкладывать друг в друга, используя все тот же оператор use,при этом модуль не должен ссылаться сам на себя ни прямо, ни косвенно —

через цепочку модулей.

Самый простой пример использования модуля — это помещение в него описаний данных. Описываем модуль array и помещаем в него описание некоторого массива:

MODULE ARRAY

REAL, DIMENSIONB0) :: A

END MODULE ARRAY,

и затем включаем этот модуль в набор подпрограмм subi, sub2 и sub3:

SUBROUTINE SUBI

USE ARRAY

END SUBROUTINE SUB1

и так далее Массив а будет доступен для всех трех подпрограмм:

PROGRAM SUBS

CALL SUB1

CALL SUB2

CALL SUB3

END PROGRAM SUBS

Модуль является идеальным местом для размещения определений производных типов и операций с ними, интерфейсных блоков и списков

NAMELIST.

Области общей памяти

Необходимо отметить, что в Фортране существует еще одно средство глобализации данных — это области общей памяти, называемые coMMON-блоками.

coMMON-блоки могут быть именованными и неименованными. Можно описать только один неименованный соммодг-блок для всей программы, именованных блоков можно описать множество. Область общей памяти описывается оператором common, полный синтаксис которого имеет вид:

COMMON [/имя_общего_блока/] список [, /имя_общего_блока/] список .,где имя_общего_блока — необязательное имя comoN-блока, а список — спи-

сок переменных, размещаемых в указанной области общей памяти. Приведем примеры именованного и безымянного блоков:

COMMON /BASE/ X, Y, Z, INDEXA0)

COMMON / / RESULTB00)

Сommon-блок представляет собой отрезок памяти, куда последовательно записываются включенные в него объекты. Общая область доступна для всех программных компонентов, объявивших ее. При этом имена переменных именованного соммоы-блока в различных программных компонентах вовсе не должны совпадать — должно совпадать полное число единиц памяти, отведенных под него. Например,

coMMON-блок /base/ в другой подпрограмме может выглядеть так:

COMMON /BASE/ AC), I, J, К(8)

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

28. Рекурсивные процедуры и функции

Процедуры и функции могут вызывать сами себя, то есть обладать свойством рекурсивности.

Предполагается, что подпрограммы не содержат обращений к себе* по умол-

чанию рекурсия подпрограмм запрещена. Подпрограмму можно объявить

рекурсивной, для этого нужно внести в ее заголовок декларацию recursive:

RECURSIVE SUBROUTINE FACTORIAL(N, NF)

тогда обращения из подпрограммы к самой себе будут разрешены. При соз-

дании рекурсивной подпрограммы необходимо построить ее алгоритм так,

чтобы выход из нее гарантировался. Рассмотрим простейшую рекурсивную

подпрограмму вычисления факториала целого числа n (листинг 7.9)'

Листинг 7.9. Пример рекурсивной процедуры

RECURSIVE SUBROUTINE FACTORIAL(N, NF)

INTEGER, INTENT(IN) :: N

INTEGER, INTENT(INOUT) :: NF

DATA NF /1/

IF(N .GT. 1) THEN

NF = NF * N

CALL FACTORIAL(N - 1, NF)

END IF

END

При каждом вызове рекурсивной подпрограммы создается новый набор ло-

кальных объектов подпрограммы. Исключением являются объекты, имею-

щие атрибут save, и объекты, начальное значение которых задается опера-

тором data. Объекты, инициализируемые в подпрограммах, получают

атрибут save автоматически, а оператор data при рекурсивном вызове вы-

полняется только один раз.

Рекурсивные функции несколько отличаются от рекурсивных процедур* ес-

ли рекурсивная функция вызывает сама себя, результат ее должен иметь

другое имя. Описанная здесь подпрограмма factorial является процедурой;

сделаем из нее рекурсивную функцию (листинг 7.10).

Листинг 7.10. Пример рекурсивной функции

INTEGER RECURSIVE FUNCTION FACTORIAL(N) RESULT(NF)

INTEGER N, NF

DATA NF /1/

IF(N .GT. 1) NF = N * FACTORIAL(N - 1)

END

Директива result помещает результат рекурсивной функции в указанную

переменную, решая проблему сохранения результата предыдущей итерации.

29. Области видимости имен и меток

Для именованных объектов и меток существует пространство, в рамках которого они доступны по своему идентификатору. Это пространство называется областью видимости. Для каждой подпрограммы определен свой набор меток; даже внутренние подпрограммы имеют свой, независимый от компонента-носителя набор. То есть метки компонента-носителя и внутренней подпрограммы могут быть одинаковыми, они не будут смешиваться.

К именованным объектам относятся переменные, именованные константы, подпрограммы (внутренние и внешние), производные типы и списки NAMELIST.

Каждая подпрограмма определяет свое пространство имен, состоящее из всех объектов, описанных в ней Это локальные объекты. Кроме локальных объектов, внутри подпрограммы могут использоваться ассоциированные (присоединенные) и глобальные объекты. Ассоциирование может происходить

через носитель (подпрограмма является внутренней подпрограммой) или через включение в компонент модуля (vse-ассоциированиё) Глобальные объекты — к ним относятся имена программных компонентов и внешние подпрограммы — не требуют объявления и автоматически доступны в любом месте программы.

Локальные именованные объекты доступны для всех операторов того программного компонента, в котором они определены, за вычетом интерфейсов. Блоки определения производных типов и внутренних подпрограмм имеют доступ к ассоциированным объектам через носитель, если только в них не объявлен локальный объект с тем же именем — локальные объекты

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

SUBROUTINE OUTSIDE

REAL А, В

CONTAINS

SUBROUTINE INSIDE

REAL В, Y

У = А + В

END SUBROUTINE INSIDE

END SUBROUTINE OUTSIDE

Имена use-ассоциированных объектов использовать в описаниях локальных объектов, вообще говоря, нельзя. Оператор:

USE имя_модуля

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

Имя каждого именованного объекта внутри блока видимости должно быть уникальным Например, определение внутренней подпрограммы с именем sin сделает недоступной одноименную встроенную процедуру.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]