Übergeben des zugewiesenen Arrays von der Unterroutine an das Hauptprogramm in fortran; verwenden oder Modul? Schnittstelle?

Aug 16 2020

Ich möchte ein Array in einer Unterroutine zuweisen und dieses Array dann im Hauptprogramm verwenden und an eine andere Unterroutine übergeben. In der Vergangenheit (F77?) Konnte die Übergabe in einem gemeinsamen Block erfolgen, aber heutzutage scheint das bevorzugte Verfahren darin zu bestehen, ein Modul zu verwenden. Wenn ich dies versuche, wie im Codebeispiel, sagt mir der Compiler

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

Anscheinend denkt das Hauptprogramm, dass 'f' ein Skalar ist. Aber ich habe diesen Code gelesen, um zu bedeuten, dass ich ihn als eindimensionales Array deklariert habe, sowohl innerhalb des Unterprogramms als auch im Hauptprogramm. Was vermisse ich?

Ich habe Variationen ausprobiert, z. B. das Deklarieren der Variablen als Teil des Moduls, aber nichts, was mir einfiel, machte die Kompilierung fehlerfrei (und einige verursachten viel mehr Fehler ;-(). Jeder Einblick wird am meisten geschätzt.

          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

Antworten

2 francescalus Aug 16 2020 at 17:19

Module in Fortran sind nicht wie Header-Dateien in anderen Sprachen, die lediglich Informationen zu an anderer Stelle definierten Dingen enthalten. Es gibt das Konzept der "verzögerten Definition" (Submodule), aber in diesem Fall sollte das Modul alles über die Subroutine sagen und nicht einfach versuchen, auf ihre Existenz hinzuweisen.

Im Beispiel der Frage haben wir: das Hauptprogramm; ein Modul subsmit Modulprozedur makef; eine externe Unterroutine makef.

Das Hauptprogramm verwendet das Modul subsund seine Prozedur makef, daher verweist im Hauptprogramm makefauf diese Modulprozedur und nicht auf die externe Unterroutine makef.

Das Modul-Unterprogramm makefenthält das Argument, fdas keine Deklarationsanweisungen enthält, was es zu einer implizit deklarierten skalaren / externen Funktion macht. Dies ist die Nachricht des Compilers. Verwendung implicit nonein Modulen, genau wie im Hauptprogramm und in der externen Unterroutine hier.

Die gesamte Definition des Unterprogramms sollte in das Modul eingefügt werden:

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

Wenn man sich alternativ auf die spätere Implementierung einer externen Prozedur beziehen möchte, kann ein Schnittstellenblock im Modul enthalten sein, ohne das Unterprogramm selbst zu deklarieren. In diesem Fall muss weiterhin die vollständige Schnittstelle angegeben werden:

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

In diesem Fall bevorzugen Sie nicht den Schnittstellenblock.

VladimirF Aug 16 2020 at 13:07

Sie haben nur die Kopie der ersten und der letzten Zeile in das Modul eingefügt. Das kann nicht funktionieren. Sie müssen das gesamte Unterprogramm in das Modul verschieben.