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

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

Вот мой интерфейсный блок:

interface
    function correctNeighLabel (A,i,j,k)
    integer :: correctNeighLabel
    integer, intent(in) :: i,j,k
    integer,dimension(:,:,:),intent(inout) :: A
    end function

    function correctNeighArray (B,d,e,f)
        character :: correctNeighArray
    integer, intent(in) :: d,e,f
    character, dimension(:,:,:),intent(inout) :: B
    end function
end interface

Мне кажется, что это не лучший вариант.

Я изучил подпрограммы, но не уверен, что это правильное решение. То, что я делаю, относительно просто, и мне нужно передать аргументы подпрограмме, но все подпрограммы, которые я видел, а) сложны (т.е. слишком сложны для функции) и б) не принимают аргументов. Они ведут себя так, как будто манипулируют переменными, не передавая их им.

Я не очень хорошо разбирался в модулях, но, судя по тому, что я видел, это не то, что нужно использовать.

Что мне следует использовать, когда и как лучше всего это сделать?


person Pureferret    schedule 07.12.2011    source источник
comment
В Фортране это 'character', а не 'char'   -  person alexurba    schedule 07.12.2011


Ответы (3)


Модули - это всегда то, что нужно использовать ;-)

Если у вас очень простая программа F90, вы можете включать функции и подпрограммы в блок 'contains':

 program simple
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end program

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

Для более сложных программ вы должны хранить все функции / подпрограммы в модулях и загружать их по мере необходимости. Таким образом, вам также не нужно определять интерфейсы:

 module mymod
   implicit none
   private
   public :: myfunc
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end module mymod

 program advanced
   use mymod, only: myfunc
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 end program advanced

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

person alexurba    schedule 07.12.2011
comment
В верхнем блоке кода вы не запускаете подпрограмму или что-то еще, называемое mysub, но закрываете ее. Это разрешено? Вы делаете то же самое во втором блоке кодирования. Это должны быть end function myfunc строки? Итак, я могу перенести свои функции в новый модуль, и он должен работать именно так, и я могу вызывать функции, как если бы они были в основной программе? Думаю, я понимаю, как это работает. Большое спасибо. - person Pureferret; 07.12.2011
comment
функция myfunc должна закрываться с завершением функции myfunc - исправлено. - person M. S. B.; 07.12.2011
comment
Требуется ли implicit none в каждой содержащейся процедуре, если модуль, содержащий эти процедуры, также имеет implicit none? - person jvriesem; 20.02.2019

Отделяя и расширяя то, что уже было сказано. Лучше поместить ваши процедуры (подпрограммы и функции) в модули и «использовать» их, потому что с их помощью вы получаете автоматическую проверку согласованности интерфейсов без особых усилий. У других способов есть недостатки. Если вы определяете интерфейс с помощью интерфейсного блока, вам нужно поддерживать три вещи вместо двух: интерфейс, саму процедуру и вызов. Если вы внесете изменения, все три должны быть изменены, чтобы они были согласованными. Если вы используете модуль, нужно заменить только два. Причина использования интерфейсного блока заключается в том, что у вас нет доступа к исходному коду (например, предварительно скомпилированной библиотеке) или исходный код находится на другом языке (например, вы используете код C через привязку ISO C).

Недостатком подхода «содержит» является то, что содержащиеся процедуры наследуют все локальные переменные родительской программы ... что не очень модульно и может сбивать с толку, если вы забудете эту «особенность».

person M. S. B.    schedule 07.12.2011

ответы alexurba и MSB как всегда правильные и полезные; Позвольте мне подробнее остановиться на одном моменте - если модули - это то, что нужно (а они есть), то для чего вообще нужны интерфейсы?

Для функций и подпрограмм в модулях: все, что use в этом модуле, может автоматически видеть эти интерфейсы; интерфейсы генерируются при компиляции модуля (эта информация, помимо прочего, попадает в файл .mod, который создается при компиляции модуля). Так что самому писать не нужно. Точно так же, когда вы используете подпрограмму CONTAINed (которая, соглашаясь с MSB, я считаю больше запутанной, чем полезной - ее гораздо лучше рассматривать как закрытие или вложенные подпрограммы, чем внешние подпрограммы), основная программа уже может явно «видеть» интерфейс, и вам не нужно его писать для нее.

Блоки интерфейса предназначены для случаев, когда вы не можете этого сделать - когда компилятор не может сгенерировать для вас явный интерфейс или когда вам нужно что-то отличное от того, что дано. Одним из примеров является использование C -Взаимодействие с Fortran в Fortran 2003. В этом случае код Fortran связывается с некоторой библиотекой C (скажем) и не может создать для вас правильный интерфейс fortran для подпрограммы C - вы должны это сделать самостоятельно, написав собственный блок интерфейса.

Другой пример - когда вы уже знаете интерфейсы подпрограмм, но хотите создать новый интерфейс, чтобы «скрыть» подпрограммы - например, когда у вас есть одна процедура, которая работает (скажем) с целыми числами, а другая - с реальными числами. , и вы хотите иметь возможность вызывать одно и то же имя подпрограммы для любой из них и позволять компилятору разбираться в ней на основе аргументов. Такие конструкции называются общие подпрограммы и существуют со времен Fortran 90. В этом случае вы создаете интерфейс явно для этой новой универсальной подпрограммы и перечисляете интерфейсы к «реальным» подпрограммам в этом блоке интерфейса.

person Jonathan Dursi    schedule 07.12.2011
comment
+1 Конечно, интерфейсы полезны, и я стараюсь как можно чаще использовать общие процедуры. - person alexurba; 07.12.2011