современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
234 8. Программные единицы Результирующая переменная подобна параметру с видом связи OUT. При входе в функцию она не определена, далее получает значение, которое затем используется в вызывающей программной единице. Результирующая переменная может использоваться в выражениях функции, и в результате вычислений она должна получить значение. Последнее значение результирующей переменной используется в выражении, из которого функция вызвана. Результирующая переменная после выполнения функции может быть не определена, если она является ссылкой и вызов функции выполнен не из выражения (разд. 3.11.8). Обычно результирующая переменная получает значение в результате присваивания. Но это необязательно. Например, в случае символьной функции результирующая переменная может быть определена после выполнения оператора (разд. 3.8.7) WRITE(имя результата, спецификатор формата) выражение Результирующая переменная может быть скаляром или массивом любого встроенного и производного типа, также она может быть и ссылкой (разд. 3.11.8). Результатом функции не может быть перенимающий размер массив. Так же как и в случае подпрограммы, функция может возвращать данные и через передаваемые по ссылке параметры (параметры с видом связи OUT или INOUT). Однако такой способ передачи данных может привести к побочным эффектам (разд. 8.11.6) и поэтому не может быть рекомендован. Пример. Найти сумму последних отрицательных элементов массивов a и b. Поиск последнего отрицательного элемента в массиве выполним в функции finel. program nel integer :: a(8) = (/1, -1, 2, -2, 3, -3, 4, -4 /) integer :: b(10) = (/1, 2, 3, 4, 5, -1, -2, -3, -4, -5 /) integer :: finel ! Объявляем тип функции print *, finel(a, 8) + finel(b, 10) ! Вызов функции из выражения end ! -9 function finel(c, n) integer finel ! Объявляем тип результирующей переменной integer c(n), i ! Используем массив заданной формы finel = 0 ! Определим результирующую переменную на do i = n, 1, -1 ! случай, если в массиве нет отрицательных if(c(i) < 0) then ! элементов finel = c(i) return ! Возвратим последний отрицательный элемент end if end do end function 235 О. В. Бартеньев. Современный ФОРТРАН 8.11. Параметры процедур Обмен данными между процедурой и вызывающей программной единицей может быть выполнен через параметры процедуры. Параметры, используемые при вызове процедуры, называются фактическими. Параметры, используемые в процедуре, называются формальными. Пример. Сформировать вектор c1 из элементов вектора a, которых нет в векторе b1. Затем сформировать вектор c2 из элементов вектора a, которых нет в векторе b2. Формирование массивов выполним в подпрограмме fobc. program part integer, parameter :: na = 10, nb1 = 5, nb2 = 7 integer :: a(na) = (/ 1, -1, 2, -2, 3, -3, 4, -4, 5, -5 /) integer :: b1(nb1) = (/ 1, -1, 2, -2, 3 /) integer :: b2(nb2) = (/ 1, -1, 2, -2, 3, -3, 4 /) integer c1(na), c2(na), nc1, nc2 call fobc(a, na, b1, nb1, c1, nc1) ! Формируем массив c1 call fobc(a, na, b2, nb2, c2, nc2) ! Формируем массив c2 write(*, *) c1(:nc1) ! -3 4 -4 5 -5 write(*, *) c2(:nc2) ! -4 5 -5 end program subroutine fobc(a, na, b, nb, c, nc) integer na, nb, a(na), b(nb) ! Входные формальные параметры integer c(na), nc ! Выходные формальные параметры integer i, j, va nc = 0 ! Число элементов в формируемом массиве loop_a: do i = 1, na ! Имя DO-конструкции использует va = a(i) ! оператор CYCLE loop_a do j = 1, nb if( va == b(j) ) cycle loop_a end do nc = nc + 1 c(nc) = va end do loop_a end subroutine fobc В операторе CALL fobc присутствуют фактические параметры. Тогда как присутствующие в операторе SUBROUTINE fobc параметры a, na, bc и m являются формальными. 8.11.1. Соответствие фактических и формальных параметров При вызове процедуры между фактическими и формальными параметрами устанавливается соответствие (формальные параметры ассоциируются с соответствующими фактическими). Так, в нашем примере при первом вызове подпрограммы fobc фактическому параметру a 236 8. Программные единицы соответствует формальный параметр a, фактическому параметру b1 - формальный параметр b и т. д. Типы соответствующих параметров совпадают. Как видно из примера, имена соответствующих фактических и формальных параметров могут различаться. В нашем примере скорее всего фактический и соответствующий ему формальный параметр будут адресовать одну и ту же область памяти. Правда, это справедливо не во всех случаях. Так, если фактическим параметром является сечение массива, то при вызове процедуры компилятор создаст его копию, которую и будет адресовать формальный параметр. При выходе из процедуры (если параметр имеет вид связи OUT или INOUT) произойдет обратная передача данных из копии в сечение- параметр. Фактическими параметрами могут быть выражения, в том числе буквальные и именованные константы, простые переменные, массивы и их сечения, элементы массивов, записи, элементы записей, строки и подстроки, а также процедуры и встроенные функции; в случае подпрограммы именем фактического параметра может быть и метка. Формальными параметрами могут быть переменные (полные объекты), процедуры и звездочка (*). Фактические и формальные параметры могут иметь атрибуты, например POINTER или TARGET. Устанавливая соответствие между фактическими и формальными параметрами, следует придерживаться приведенных в табл. 8.2 правил. Таблица 8.2. Фактические и формальные параметры Фактический параметр Формальный параметр Скалярное выражение Скалярная переменная Нескалярное выражение (массив, сечение массива...) Массив Процедура Процедура *Метка (только для подпрограмм) * (звездочка) Замечания: 1. Если формальный параметр является ссылкой, то и соответствующий фактический параметр тоже должен быть ссылкой. 2. Если фактическим параметром является строка, то формальным параметром может быть строка, перенимающая длину (разд. 3.8.2). 3. Если фактическим параметром является элемент массива, то соответствующим формальным параметром может быть массив (разд. 4.9.1). 237 О. В. Бартеньев. Современный ФОРТРАН 4. Если фактическим параметром является массив, то формальным параметром может быть массив заданной формы, или перенимающий форму массив, или перенимающий размер массив (разд. 4.9). 5. Если фактический параметр является внешней процедурой, то он должен иметь атрибут EXTERNAL. Если же фактический параметр является встроенной процедурой, то он должен быть объявлен с атрибутом INTRIN- SIC. 8.11.2. Вид связи параметра Формальные параметры разделяются на входные, выходные и входные/выходные. Входной формальный параметр получает свое значение от соответствующего фактического параметра. Выходной - передает свое значение соответствующему фактическому параметру. Входные/выходные - осуществляют связь в двух направлениях. В подпрограмме fobc (разд. 8.11) формальные параметры a, na, b и nb являются входными. Параметры c и nc – выходными, т. е. их значения определяются в процедуре и потом уже используются в вызывающей программной единице. Такое разделение формальных параметров примера на входные/выходные мы выполнили, исходя из совершаемых программой действий. На самом деле вид связи формального параметра можно задать явно, использовав атрибут INTENT, например: subroutine fobc(a, na, b, nb, c, nc) integer, intent(in) na, nb, a(na), b(nb) integer, intent(out) c(na), nc integer i, j, va Для задания атрибута INTENT может быть применен оператор INTENT: subroutine fobc(a, na, b, nb, c, nc) integer na, nb, nc, a(na), b(nb), c(na), i, j, va intent(in) na, nb, a, b intent(out) c, nc Синтаксис оператора INTENT: INTENT (spec) [::] vname Синтаксис атрибута INTENT: type-spec, INTENT (spec) [, attrs] :: vname spec - вид связи формального параметра, spec может принимать одно из трех значений: • IN - формальный параметр является входным и не может быть изменен или стать неопределенным в процедуре. Ассоциированный с ним фактический параметр может быть выражением, например константой или переменной; 238 8. Программные единицы • OUT - формальный параметр является выходным. При входе в процедуру такой формальный параметр всегда не определен и поэтому должен получить значение до его использования. Ассоциированный с ним фактический параметр должен быть определяемым, например переменной, подстрокой или элементом записи; • INOUT - формальный параметр может как получать данные от фактического параметра, так и передавать данные в вызывающую программную единицу. Как и в случае вида связи OUT, ассоциированный с ним фактический параметр должен быть определяемым (не должен быть, например, константой). vname - разделенные запятыми имена формальных параметров. type-spec - спецификация любого типа данных. attrs - список иных атрибутов формального параметра. Если атрибут INTENT не задан, то способ использования формального параметра определяет ассоциированный с ним фактический параметр. Так, формальный параметр не должен переопределяться в процедуре, если ассоциированный с ним фактический параметр выражение или константа. real :: length, x = 3.0, y = 4.0, r r = length(3.0, 4.0) ! Этот вызов ошибочен r = length(x, y) ! Этот вызов допустим end real function length(x, y) ! Первый вызов ошибочен, поскольку real x, y ! формальные параметры x и y call square(x, y) ! переопределяются в подпрограмме square length = sqrt(x + y) end function subroutine square(x1, y1) real, intent(inout) :: x1, y1 x1 = x1 * x1 y1 = y1 * y1 end subroutine Если формальный параметр имеет вид связи IN, то он не должен быть использован в качестве фактического параметра, ассоциируемого с формальным параметром, вид связи которого OUT или INOUT. Так, в предыдущем примере формальные параметры x, y функции length не должны иметь вид связи IN. Если функция задает перегружаемую операцию, то формальные параметры обязаны иметь вид связи IN. Если подпрограмма определяет задаваемое присваивание, то первый ее формальный параметр должен иметь вид связи OUT или INOUT, а второй - IN. Недопустимо использование атрибута INTENT: • для формальных параметров с атрибутом POINTER; 239 О. В. Бартеньев. Современный ФОРТРАН • для формальных параметров - процедур (формальных процедур). 8.11.3. Явные и неявные интерфейсы Интерфейс между процедурой и вызывающей ее программной единицей считается заданным, если вызывающей программной единице известны имя процедуры, ее вид (подпрограмма или функция), свойства функции (если процедура - функция), имена, положение и свойства формальных параметров. В Фортране 77 интерфейс к вызываемой процедуре полностью неизвестен и он устанавливается при вызове по списку фактических параметров. Устанавливаемый таким образом интерфейс называется неявным. Такие вызовы могут быть причиной ряда ошибок, поскольку компилятор не всегда имеет возможность, например, проверить, соответствуют ли фактические и формальные параметры так, как это им положено. Вызовы внешних процедур с неявным интерфейсом допустимы и в современном Фортране. В случае функции при неявном интерфейсе ее тип и разновидность типа задаются в одном из операторов объявления типа вызывающей программной единицы или устанавливаются в соответствии с действующими правилами умолчания. Однако формальные параметры процедур и процедуры-функции могут обладать дополнительными свойствами, о которых должен знать компилятор, чтобы правильно организовать доступ к коду процедуры. Чтобы сообщить компилятору такие сведения, между вызывающей программной единицей и процедурой должен существовать явный интерфейс. В случае внутренней процедуры вызывающая программная единица и ее процедура компилируются как единое целое, поэтому компилятор знает все о любой внутренней процедуре, т. е. между внутренней процедурой и вызывающей программной единицей существует явный интерфейс. Модульная процедура вызывается либо в самом модуле, либо из программной единицы, где вызову предшествует оператор USE для этого модуля. Поэтому в обоих случаях компилятор знает все о вызываемой процедуре и, следовательно, ее интерфейс является явным. Также все встроенные процедуры заведомо обладают явным интерфейсом. В случае внешней процедуры к ней также может быть установлен явный интерфейс. Это делается при помощи интерфейсного блока, имеющего вид: INTERFACE тело интерфейса END INTERFACE Тело интерфейса содержит описание одного и более интерфейсов процедур. Как правило, интерфейс процедуры - это точная копия заголовка 240 8. Программные единицы процедуры, объявлений ее формальных параметров, типа функции в случае процедуры-функции и оператора END процедуры. Однако в интерфейсном блоке: • имена параметров могут отличаться от имен соответствующих формальных параметров процедуры; • могут быть добавлены дополнительные спецификации (например, объявления локальных переменных) за исключением описаний внутренних процедур и операторов DATA и FORMAT; • можно представлять ту же информацию при помощи другой комбинации операторов объявления. Пример: subroutine sub1(i1, i2, r1, r2) integer :: i1, i2 real :: r1, r2 ! В разделе объявлений процедуры атрибут ! OPTIONAL может быть опущен. Достаточно того, ! что он задан в интерфейсном блоке end subroutine sub1 program idem interface ! Интерфейс подпрограммы sub1 subroutine sub1(int1, int2, real1, real2) integer :: int1, int2 real, optional :: real1, real2 end subroutine sub1 end interface Также может быть задан интерфейс внешних процедур, написанных на других языках программирования, например на ассемблере или CИ. Наличие таких интерфейсов позволяет создавать разноязычные приложения [1]. Задание интерфейса означает, что упоминаемые в нем процедуры рассматриваются как внешние. Любая встроенная процедура с таким же именем становится недоступной. Такой же эффект имеет и упоминание имени процедуры в операторе EXTERNAL. Одновременное упоминание имени процедуры в теле интерфейса и операторе EXTERNAL недопустимо. Интерфейсный блок размещается среди операторов описания. Удобнее всего собрать интерфейсные блоки в одном или нескольких модулях и подключать их по мере необходимости при помощи оператора USE. Задание явного интерфейса необходимо, если: • процедура имеет необязательные формальные параметры; • результатом процедуры-функции является массив (разд. 4.11); • формальным параметром процедуры является перенимающий форму массив (разд. 4.9.2), ссылка или ее адресат (разд. 3.11.8); 241 О. В. Бартеньев. Современный ФОРТРАН • длина результата символьной функции не является константой и не перенимается из вызывающей программной единицы; • результатом процедуры-функции является ссылка; • процедура является динамической библиотекой. Также интерфейсные блоки употребляются: • при вызове процедуры с ключевыми словами (разд. 8.11.4); • при использовании задаваемого присваивания (разд. 8.12.2); • при использовании задаваемых операций (разд. 8.12.2); • при использовании в вызове родового имени (разд. 8.12); • для доступа к внешним, написанным на других языках процедурам [1]. 8.11.4. Ключевые и необязательные параметры При некоторых вызовах процедуры часть фактических параметров может не использоваться. Примером такой процедуры может послужить встроенная функция SUM(array [, dim] [, mask]) (разд. 4.12.1), имеющая два необязательных параметра dim и mask. В этом случае соответствующие формальные параметры должны быть объявлены с атрибутом OPTIONAL. Как и другие атрибуты, OPTIONAL может быть использован в операторе объявления типа и как самостоятельный оператор. Пример. Создать функцию npe(array, me, sig), возвращающую: • сумму me первых положительных элементов массива array, если sig > 0; • сумму me первых отрицательных элементов массива array, если sig < 0; • сумму me первых элементов массива array, если sig = 0 или отсутствует; • сумму всех заданных посредством sig-знака элементов массива, если отсутствует параметр me. program tesop integer, parameter :: m = 3, n = 10 integer :: a(n) = (/ 1, -1, 2, -2, 3, -3, 4, -4, 5, -5 /) ! Необходимо явно задать интерфейс к процедуре interface ! с необязательными формальными параметрами integer function npe(array, me, sig) integer, intent(in) :: array(:) integer, intent(in), optional :: me, sig end function npe end interface print *, npe(a, m, 1) ! 6 print *, npe(a, sig = -1) ! -15 print *, npe(a) ! 0 end program tesop integer function npe(array, me, sig) integer, intent(in) :: array(:) integer, intent(in), optional :: me, sig integer mval, sval 242 8. Программные единицы integer, allocatable :: temp(:) if(.not. present(sig)) then ! Использовать неассоциированный sval = 0 ! необязательный формальный параметр else ! можно только в качестве аргумента sval = sig ! функции PRESENT end if if(present(me)) then mval = me else mval = size(array) end if select case(sval) case(1:) ! Размер temp может быть меньше mval allocate(temp(min(mval, count(array > 0)))) temp = pack(array, array > 0) case(:-1) allocate(temp(min(mval, count(array < 0)))) temp = pack(array, array < 0) case(0) allocate(temp(mval)) temp = array(1:mval) endselect npe = sum(temp) ! Возвращаемый результат deallocate(temp) end function npe Синтаксис оператора OPTIONAL: OPTIONAL [::] vname Синтаксис атрибута OPTIONAL: type-spec, OPTIONAL [, attrs] :: vname type-spec - спецификация любого типа данных. vname - разделенные запятыми имена формальных параметров. Атрибут может быть использован только для формальных параметров процедур. Интерфейс процедуры, содержащей атрибут OPTIONAL, должен быть описан явно. Формальный параметр, имеющий атрибут OPTIONAL, может дополнительно иметь только атрибуты DIMENSION, EXTERNAL, INTENT, POINTER и TARGET. Если необязательный формальный параметр не задан, то ему не может быть присвоено значение и его нельзя использовать в выражении. Для определения того, задан формальный параметр или нет, используется встроенная функция PRESENT(a) |