передача выделенного массива из подпрограммы в основную программу в fortran; использовать или модуль? интерфейс?

Aug 16 2020

Я хочу выделить массив в подпрограмме, а затем использовать этот массив в основной программе и передать его какой-либо другой подпрограмме. В прошлом (F77?) Передача могла выполняться в общем блоке, но в настоящее время, похоже, предпочтительной процедурой является использование модуля. Когда я пробую это, как в примере кода, компилятор сообщает мне

Rank mismatch in argument ‘f’ at (1) (scalar and rank-1)

Очевидно, основная программа думает, что 'f' является скаляром: но я прочитал этот код, чтобы обозначить, что я объявил его как одномерный массив как внутри подпрограммы, так и в основной программе. Что мне не хватает?

Я пробовал различные варианты, такие как объявление переменных как части модуля, но ничто из того, что я мог придумать, не делало компиляцию безошибочной (а некоторые приводили к еще большему количеству ошибок ;-(). Любое понимание очень ценно.

          module subs
        contains
        subroutine makef(f)
        end subroutine makef
      end module subs
c-----------------------------------------------------------------------
      program work

      use subs
      implicit none
        real, allocatable :: f(:)

      call makef(f)

      write (*,*) f
      stop
      end
c---------------------------------------------------------------------
      subroutine makef(f)
      implicit none

      real, allocatable, intent(out) :: f(:)
      integer :: i
      integer :: is

      is=10
      allocate(f(-is:is))

      do i=-is,is
        f(i)=i
      end do
      return
      end subroutine makef

Ответы

2 francescalus Aug 16 2020 at 17:19

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

В примере вопроса у нас есть: основная программа; модуль subsс модульной процедурой makef; внешняя подпрограмма makef.

Основная программа использует модуль subsи его процедуру makef, поэтому ссылка в основной программе makefотносится к этой модульной процедуре, а не к внешней подпрограмме makef.

Подпрограмма модуля makefимеет аргумент, fкоторый не имеет деклараций, что делает его неявно объявленной скалярной / внешней функцией. Это сообщение компилятора. Используется implicit noneв модулях так же, как здесь в основной программе и внешней подпрограмме.

Полное определение подпрограммы должно быть помещено в модуль:

module subs
  implicit none
contains
  subroutine makef(f)
    real, allocatable, intent(out) :: f(:)
    integer :: i
    integer :: is

    is=10
    allocate(f(-is:is))

    do i=-is,is
      f(i)=i
    end do
  end subroutine makef
end module subs

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

module subs
  implicit none

! An interface block to give an explicit interface to the external subroutine makef
  interface
     subroutine makef(f)
       implicit none
       real, allocatable, intent(out) :: f(:)
     end subroutine makef
  end interface
end module subs

В этом случае не отдавайте предпочтение интерфейсному блоку.

VladimirF Aug 16 2020 at 13:07

Вы поместили в модуль только копию первой и последней строки. Это не сработает. Вы должны переместить всю подпрограмму в модуль.