современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
243 О. В. Бартеньев. Современный ФОРТРАН где a - необязательный формальный параметр. Функция возвращает .TRUE., если формальный параметр a ассоциирован с фактическим, и .FALSE. - в противном случае. Необязательный формальный параметр может использоваться внутри процедуры в качестве фактического параметра. Если такой необязательный параметр отсутствует, то он рассматривается как отсутствующий и в процедуре следующего уровня. Отсутствующие параметры могут распространяться на любую глубину вызова. Отсутствующий параметр может появляться в качестве фактического параметра только как полный объект, а не как его подобъект. В Фортране 77 расположение соответствующих формальных и фактических параметров в списке параметров должно совпадать, т. е. первый формальный параметр ассоциируется с первым фактическим и т. д. Если ассоциируемый формальный параметр определяется по положению фактического параметра в списке параметров, то такой фактический параметр называется позиционным. В Фортране это правило может быть нарушено, если использовать при вызове процедуры параметры с ключевыми словами. Ключевые слова - это имена формальных параметров, присвоенные им в интерфейсном блоке Например, допустимы вызовы функции npe: result = npe(sig = 1, array = a, me = m) result = npe(a, sig = 1, me = m) result = npe(a, sig = 1) В первом вызове все параметры должны предваряться ключевыми словами. Во втором и третьем - первый параметр является позиционным, поэтому он может быть задан без ключевого слова. В третьем случае не задан второй формальный параметр, поэтому для установления связи с формальным параметром sig необходимо использовать вызов с ключевым словом - именем формального параметра. Однако позиционные параметры не могут появляться в списке фактических параметров после первого появления параметра с ключевым словом. Так, ошибочен вызов result = npe(array = a, m, 1) 8.11.5. Ограничения на фактические параметры Стандарт устанавливает два ограничения на фактические параметры: • должны быть исключены любые действия, влияющие на значение и доступность фактического параметра в обход соответствующего формального параметра; • если хотя бы часть фактического параметра получает значение от формального параметра, то в процедуре ссылаться на этот фактический параметр можно только через формальный параметр. 244 8. Программные единицы Для иллюстрации ограничений рассмотрим пример: integer a(10) /10*2/, x, xx, y /2/ common /cb/ x, xx character(10) st /'??????????'/ call rest1(x, xx, a(1:7), a(4:10)) ! Согласно ограничению 1 в rest1 call rest2(y, st(3:7)) ! нельзя менять значение a(4:7) print *, x, xx, a(5), y, ' ', st contains subroutine rest2(y2, st2) integer y2 character(*) st2 y2 = 4 ! Верно y = 6 ! Нарушено ограничение 2 st2 = '&&&&&' ! Верно st = '##########' ! Нарушено ограничение 2 end subroutine rest2 end subroutine rest1(x2, xx2, a, a2) integer x2, xx2, a(*), a2(*) common /cb/ x, xx x = 1 ! Нарушено ограничение 1 x2 = 11 ! Верно xx2 = 3 ! Верно xx = 33 ! Нарушено ограничение 1 a(1:3) = 22 ! Верно a2(5:7) = 44 ! Верно a(4:7) = 5 ! Нарушено ограничение 1 a2(1:4) = 7 ! Нарушено ограничение 1 end Хотя пример насыщен нарушениями, CVF и FPS не выдадут ни одного сообщения или предупреждения об ошибке. Однако это совсем не означает, что программа отработает правильно. В общем случае результат непредсказуем. Это видно, в частности, из выведенных результатов: CVF: 11 1107558400 7 6 ########## FPS: 11 1107558400 5 6 ########## Аналогичным образом если переменная, например xx,доступна процедуре rest1 через модуль и одновременно ассоциируется с формальным параметром xx2 этой процедуры, то будет нарушено ограничение 1 при попытке изменить значение xx в процедуре rest1. 8.11.6. Запрещенные побочные эффекты Стандарт разрешает не вычислять часть выражения, если значение этого выражения может быть определено и без этого. Так, в примере 245 О. В. Бартеньев. Современный ФОРТРАН logical g, flo real :: x = 5.0, y = 4.0, z = 7.0 g = x > y .or. flo(z) print *, g, z ! FPS: T 7.0000 end ! CVF: T 100.0000 logical function flo(z) z = 100 flo = .true. end function flo в FPS не будет выполнено обращение к логической функции flo. В соответствии с положениями стандарта значение переменной z должно после вычисления выражения стать неопределенным. Хотя в FPS переменная z и сохранит свое значение, а в CVF изменит, совершенно очевидно, что следует избегать подобных вызовов функции. Действительно, если бы значение x было равно 3.0, то после вычисления выражения в FPS мы получили бы совсем иное значение для z - число 100.0. Другой пример, когда стандарт допускает неполное вычисление выражения: character(len = 2) :: stre, st1 = 'd1', st2 = 'd2' ! stfun - символьная функция. Стандарт разрешает не выполнять вызов stfun, ! поскольку длина результата stre равна st1, и он полностью определяется первым ! операндом выражения st1 // stfun(st2) stre = st1 // stfun(st2) print *, st2 contains character(2) function stfun(st2) character(*) st2 st2 = 'd3' stfun = 'd4' end function stfun end Заметим, однако, что и CVF и FPS обратятся к функции stfun и переменная st2 получит значение 'd3'. Существует и другое ограничение: обращение к функции не должно переопределять значение переменной, фигурирующей в том же операторе, или влиять на результат другой функции, вызываемой в том же операторе. Например, в d = max(dist(p, q), dist(q, r)) функция dist не должна переопределять переменную q. Подобных эффектов можно избежать, если программировать процедуру в виде функции лишь в том случае, когда в процедуре только один выходной параметр. 246 8. Программные единицы 8.12. Перегрузка и родовые интерфейсы 8.12.1. Перегрузка процедур Иногда полезно иметь возможность обращаться к нескольким процедурам при помощи одного имени. Реализовать подобную возможность можно, объединяя посредством родового интерфейса различные процедуры под одним родовым именем. Имена объединяемых процедур называются специфическими. Сам же механизм вызова разных процедур под одним именем называется перегрузкой. Механизм перегрузки реализован при разработке встроенных процедур (см. разд. 6.3). Построим, например, функцию mymax(arg1, arg2), возвращающую максимальное значение из двух ее параметров. Параметры функции должны быть одного из следующих типов: INTEGER(4), REAL(4) или CHARACTER(*). Тип результата функции совпадает с типом параметров. На самом деле для каждого типа параметров придется создать свою функцию, например inmax, remax и chmax, а затем, применив родовой интерфейс, мы объединим созданные функции под одним родовым именем. program getest interface mymax ! Задание родового интерфейса function inmax (int1, int2) ! mymax - родовое имя для функций integer(4) inmax, int1, int2 ! inmax, remax, chmax end function inmax function remax (re1, re2) ! inmax, remax, chmax - специфические real(4) remax, re1, re2 ! имена функций, объединенных под end function remax ! одним родовым именем mymax function chmax (ch1, ch2) character(*) ch1, ch2 character(len = max(len(ch1), len(ch2))) chmax end function chmax end interface integer(4) :: ia = 1, ib = 2 real(4) :: ra = -1, rb = -2 character(5) :: cha = 'abcde', chb = 'ABCDE' print *, mymax(ia, ib) ! 2 print *, mymax(ra, rb) ! -1.000000 print *, mymax(cha, chb) ! abcde end program getest function inmax(int1, int2) integer(4) inmax, int1, int2 if(int1 >= int2) then inmax = int1 else inmax = int2 end if end function inmax 247 О. В. Бартеньев. Современный ФОРТРАН function remax(re1, re2) real(4) remax, re1, re2 if(re1 >= re2) then remax = re1 else remax = re2 end if end function remax function chmax(cha1, cha2) character(*) cha1, cha2 character(len = max(len(cha1), len(cha2))) chmax if(lge(cha1, cha2)) then chmax = cha1 else chmax = cha2 end if end function chmax Родовой интерфейс можно задать более компактно, если функции являются модульными процедурами. В этом случае интерфейс к ним задан явно и в создаваемый для родового имени интерфейсный блок вставляется оператор MODULE PROCEDURE список имен процедур в котором перечисляются имена всех модульных процедур для перегрузки. Например: module gemod interface mymax module procedure inmax, remax, chmax end interface contains function inmax(int1, int2) end function inmax function remax(re1, re2) end function remax function chmax(cha1, cha2) end function chmax end module gemod program getest use gemod print *, chmax('abcde', 'ABCDE') ! Вызов процедуры можно выполнить, end program getest ! используя ее специфическое имя 248 8. Программные единицы Замечание. Фортран 95 позволяет завершать интерфейсный блок родовым именем. Например: interface mymax ! Задание родового интерфейса module procedure inmax, remax, chmax end interface mymax ! Завершаем блок родовым именем mymax Ту же форму задания интерфейса можно применить и в том случае, если в модуле содержатся только объединяемые под родовым именем процедуры: program getest use fuma ! Модуль fuma содержит функции inmax, remax, interface mymax ! chmax, но не содержит родового интерфейса module procedure inmax, remax, chmax end interface print *, chmax('abcde', 'ABCDE') ! abcde end program getest Объединяемые процедуры могут иметь разное число параметров. Также под одним именем могут быть перегружены и подпрограммы и функции. В интерфейсном блоке родовое имя может совпадать с любым специфическим именем процедуры этого блока. Родовое имя может также совпадать с другим доступным, например через use-ассоциирование, родовым именем. Тогда с помощью этого имени могут быть вызваны все охватываемые им процедуры. Все процедуры, объединяемые под одним родовым именем, должны различаться настолько, чтобы для каждого конкретного вызова можно было однозначно выбрать одну из объединенных процедур. Для этого в каждой паре перегружаемых процедур хотя бы одна должна иметь обязательный параметр, удовлетворяющий сразу двум условиям: • по своему положению в списке параметров он либо вообще не имеет аналога среди формальных параметров другой процедуры, либо соответствует параметру, имеющему другой тип или разновидность типа или другой ранг; • формальный параметр с таким же именем либо отсутствует в другой процедуре, либо присутствует, но имеет другой тип или разновидность типа или другой ранг. Пример нарушения второго условия: interface fu12 function f1(x, i) ! Каждый из формальных параметров f1 имеет real f1, x ! аналог среди формальных параметров функции f2 integer i ! И наоборот, каждый из формальных параметров f2 end function f1 ! имеет аналог среди формальных параметров f1 function f2(i, x) real f2, x integer i 249 О. В. Бартеньев. Современный ФОРТРАН end function f2 end interface Компилятор CVF, получивший такие интерфейсы, выдаст сообщение: Error: The type/rank/keyword signature for this specific procedure matches an- other specific procedure that shares the same generic-name. [F2] function f2(i, x). 8.12.2. Перегрузка операций и присваивания Область применения встроенной операции можно расширить. Это выполняется при помощи интерфейсного блока, заголовок которого имеет вид: INTERFACE OPERATOR(задаваемая операция) Все остальные компоненты интерфейсного блока такие же, как и при перегрузке процедур. Задающая операцию процедура должна обязательно быть функцией с одним (в случае унарной операции) или двумя параметрами, имеющими вид связи IN. Параметры функции должны быть обязательными. Результатом функции не может быть перенимающая длину строка. Такой блок связывает задаваемую операцию с одной или несколькими функциями, задающими выполняемые этой операцией действия. Например, можно задать операцию сложения переменных производного типа. Тогда в случае применения операции в зависимости от типа ее операндов будет выполняться либо встроенная операция сложения, если операнды числовые, либо заданная операция, если типы операндов совпадают с типами формальных параметров заданной в интерфейсном блоке функции. Изложенный механизм задания операции называется перегрузкой операции. module tdes ! Демонстрация перегрузки операции сложения type ire integer a ! Перегрузка операций для производных типов real ra ! необходима, поскольку для них не существует end type ire ! ни одной встроенной операции end module tdes module plup use tdes interface operator(+) ! Задание операции сложения для типа ire module procedure funir end interface contains function funir(rec1, rec2) ! Параметры задающей операцию функции type(ire) funir ! должны иметь вид связи IN type(ire), intent(in) :: rec1, rec2 funir = ire(rec1.a + rec2.a, rec1.ra + rec2.ra) end function funir end module plup 250 8. Программные единицы program top use plup ! Тип ire передается через модули plup - tdes integer :: ia = 1, ib = -1, ic type(ire) :: t1 = ire(1, 1.0), t2 = ire(2, 2.0), t3 = ire(3, 3.0), t4 ic = ia + ib ! Выполняется встроенная операция сложения t4 = t1 + t2 + t3 ! Выполняется заданная операция сложения print *, ic, t4 ! 0 6 6.000000 end При перегрузке встроенной операции нельзя изменять число ее операндов. Так, нельзя задать унарную операцию умножения. Поскольку операции отношения имеют две формы, например (.LE. и <=), то заданный для них интерфейс распространяется на каждую из форм. Таким же образом можно ввести и новую операцию. Имя вводимой операции должно обрамляться точками. Например, для обозначения операции сложения переменных типа ire можно было бы ввести операцию .plus.: interface operator(.plus.) Тогда применение вновь введенной операции может быть таким: t3 = t1 .plus. t2 .plus. t3 Как и встроенная, вновь вводимая операция может быть распространена на разные типы операндов. Также можно выполнить перегрузку присваивания. Интерфейсный блок при перегрузке присваивания имеет заголовок INTERFACE ASSIGNMENT(=) Все остальные компоненты интерфейсного блока такие же, как и при перегрузке процедур. Задающая присваивание процедура должна обязательно быть подпрограммой с двумя формальными параметрами, первый из которых имеет вид связи OUT или INOUT, а второй - IN. Параметры подпрограммы должны быть обязательными. Первый параметр подпрограммы в результате выполнения заданного присваивания будет содержать его результат, во второй - передается значение правой части присваивания. Пример. Задать присваивание для выполнения инициализации производного типа данных. module tic type icha integer a, b character(10) fi, se end type icha end module tic module oves use tic 251 О. В. Бартеньев. Современный ФОРТРАН interface assignment(=) ! Задание присваивания для инициализации записи module procedure assir end interface contains subroutine assir(rec, k) type(icha), intent(out) :: rec integer, intent(in) :: k integer :: stlen stlen = len(rec%fi) rec = icha(k, k, repeat(char(k), stlen), repeat(char(k), stlen)) end subroutine assir end module oves program top use oves ! Тип ire доступен посредством use-ассоциирования type(icha) :: t ! через модули oves - tic t = 35 ! Выполняется заданное присваивание print '(2i4, 2(1x,a))', t ! 35 35 ########## ########## end Если две процедуры, задающие одну родовую операцию или присваивание, имеют одно и то же число обязательных параметров, то для однозначности вызова одна из них должна иметь по крайней мере один формальный параметр, который по своему положению в списке параметров соответствует параметру другой процедуры, имеющему либо другой тип, либо другую разновидность типа, либо другой ранг. Это правило распространяется на случай, когда более двух процедур имеют одну родовую операцию или задают присваивание. 8.12.3. Общий вид оператора INTERFACE Оператор INTERFACE применяется для явного задания интерфейса к внешней процедуре, родового интерфейса, родовой операции и присваивания. Его синтаксис: INTERFACE [родовое описание] [тело интерфейса] [MODULE PROCEDURE список имен процедур] END INTERFACE где родовое описание - это родовое имя, или OPERATOR(определяемая операция) или ASSIGNMENT(=) 252 8. Программные единицы тело интерфейса - задает характеристики внешних или формальных процедур и представляет в случае функции заголовок функции [раздел описаний] END [FUNCTION[имя функции]] либо в случае подпрограммы заголовок подпрограммы [раздел описаний] END [SUBROUTINE [имя подпрограммы]] Оператор MODULE PROCEDURE может появляться в интерфейсном блоке, лишь когда присутствует родовое описание. При этом все процедуры списка имен процедур должны быть доступными модульными процедурами. Характеристики модульных процедур не должны появляться в интерфейсном блоке. Процедура, объявленная в интерфейсном блоке, обладает атрибутом EXTERNAL. Она не может быть объявлена внешней посредством атрибута или оператора EXTERNAL в программной единице, в которой присутствует или доступен через use-ассоциирование интерфейсный блок с этой процедурой. Для процедуры в блоке видимости может быть задан лишь один интерфейсный блок. Внутренние, модульные и встроенные процедуры имеют явно заданный интерфейс, и их имена не должны появляться в интерфейсном блоке. Исключение составляет случай, когда необходимо задать для них родовое имя. При этом имена модульных процедур задаются оператором MODULE PROCEDURE. Если же имя объявленной в интерфейсном блоке процедуры совпадает с именем встроенной процедуры, то такая встроенная процедура становится недоступной. В то же время должна существовать внешняя процедура с таким же именем. Если имя процедуры интерфейсного блока совпадает с именем формального параметра процедуры, в которой задан интерфейсный блок, то такой формальный параметр является формальной процедурой. Тело интерфейса не может содержать операторы ENTRY, DATA, FOR- MAT, объявления операторных функций. Можно, правда, задать самостоятельный ENTRY-интерфейс, использовав в теле интерфейса имя точки входа в качестве имени процедуры. Программная единица BLOCK DATA не может содержать интерфейсный блок. |