Требуются ли когда-нибудь блоки интерфейса для компиляции Фортрана? - PullRequest
0 голосов
/ 15 февраля 2019

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

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

Моя программа:

    program test
        implicit none
        real :: x, y, func

        x = 3
        y = func(x)
        print *, y
    end program test

И файл функции:

    function func(x)
        implicit none
        real :: x, func
        func = x**3
    end function func

Затем я скомпилирую его, используя gfortran -o test test.f90 func.f90 икод работает как положено.Мой вопрос: почему мне не нужно включать интерфейсный блок в мой программный файл?Это просто вопрос хорошей практики, или определение func в качестве реальной переменной служит сокращением?Я на Windows, установив gfortran через minGW.

В качестве дополнительного вопроса, если я вместо этого использую подпрограмму:

    subroutine func(x,y)
        implicit none
        real :: x,y
        y = x**3
    end subroutine func

И измените строку y = func(x) на call func(x,y) тогда код будет работать нормально без какого-либо блока интерфейса или объявления.Почему это?

Ответы [ 3 ]

0 голосов
/ 15 февраля 2019

Объявление real :: func в основной программе здесь объявляет func как функцию с (по умолчанию) реальным результатом.В результате у этой функции есть интерфейс в основной программе, поэтому вполне допустимо ссылаться на эту функцию с помощью y = func(x).

Интерфейс в этом случае неявный .Таким образом, основная программа знает ровно три вещи о func:

  • это функция (с таким именем);
  • она имеет атрибут external;
  • имеет реальный результат.

Ссылка на функцию совместима с этими знаниями.Кроме того, то, как вы ссылаетесь на функцию, точно соответствует свойствам самой функции.

Точно так же в случае подпрограммы call func(x,y) сообщает основной программе ровно три вещи, опять же с неявным интерфейсом:

  • это подпрограмма (с таким именем);
  • имеет атрибут external;
  • принимает два реальных аргумента.

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

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

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

0 голосов
/ 15 февраля 2019

В некоторых случаях необходимы интерфейсные блоки.Например, если вызываемая подпрограмма использует массив указателей, размещаемых или предполагаемых фигур (этот список не является полным, подробнее см. Стандарт):

integer, pointer :: x(:,:)  ! pointer attribute
integer, allocatable :: x(:,:)  ! pointer attribute
integer :: a(:,:)           ! assumed shape array

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

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

0 голосов
/ 15 февраля 2019

Почему мне не нужно включать интерфейсный блок в мой программный файл?

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

module func_m
contains
    function func(x)
        implicit none
        real :: x, func
        func = x**3
    end function func
end module func_m

Затем напишите use func_m в основной программе, перед implicit none: gfortran -c func_m.f90, gfortran -c test.f90 и gfortran -o test test.o func_m.o.

Когда вы используете модули, компилятор провериттип аргументов функций.Вам также не нужно объявлять real :: func, поскольку объявления взяты из модуля.

Когда вы компилируете как "простой" объектный файл, компилятор просто вызывает любую функцию с именем func без проверки, если такая функция задана в объектном файле.

Интерфейсный блок является своего рода «между ними».В вашем случае вы можете добавить один в программный файл.Это заставит вас следовать этой декларации в программе.Но это не помешает связать неправильные функции во время соединения: нет гарантии, что интерфейс правильный.Это в основном полезно, если вам нужно вызвать код C или FORTRAN 77 от кого-то другого, для которого вы не можете использовать модули.

И изменить строку y = func (x) для вызова func (х, у) тогда код будет работать нормально без какого-либо блока интерфейса или объявления.Почему это так?

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

...