передача выделенного массива из подпрограммы в основную программу в fortran; использовать или модуль? интерфейс?
Я хочу выделить массив в подпрограмме, а затем использовать этот массив в основной программе и передать его какой-либо другой подпрограмме. В прошлом (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
Ответы
Модули в 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
В этом случае не отдавайте предпочтение интерфейсному блоку.
Вы поместили в модуль только копию первой и последней строки. Это не сработает. Вы должны переместить всю подпрограмму в модуль.