Подтвердить что ты не робот

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

 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

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

Ответ 2

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

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

Ответ 3

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

Для функций и подпрограмм в модулях все, что use, этот модуль может автоматически видеть эти интерфейсы; интерфейсы генерируются при компиляции модуля (эта информация, среди прочего, входит в файл .mod, сгенерированный при компиляции модуля). Поэтому вам не нужно писать это самостоятельно. Аналогично, когда вы используете подпрограмму CONTAIN ed (которая, соглашаясь с MSB, я нахожу более запутанной, а затем полезной), их гораздо лучше воспринимают как закрытия или вложенные подпрограммы, чем внешние подпрограммы), основная программа уже может "видеть" интерфейс явно, и вам не нужно его выписывать.

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

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