Suche…


Bemerkungen

Funktionen und Unterprogramme zusammen mit Modulen sind die Werkzeuge, um ein Programm in Einheiten zu zerlegen. Dies macht das Programm lesbarer und überschaubarer. Jede dieser Einheiten kann als Teil des Codes betrachtet werden, der idealerweise isoliert zusammengestellt und getestet werden könnte. Die Hauptprogramme können solche Unterprogramme (Funktionen oder Unterprogramme) aufrufen (oder aufrufen), um eine Aufgabe auszuführen.

Funktionen und Unterprogramme unterscheiden sich in folgendem Sinn:

  • Funktionen geben ein einzelnes Objekt zurück und ändern normalerweise die Werte ihrer Argumente nicht (dh sie wirken wie eine mathematische Funktion!);
  • Subroutinen führen normalerweise eine kompliziertere Aufgabe aus und ändern normalerweise ihre Argumente (falls vorhanden) sowie andere Variablen (z. B. diejenigen, die in dem Modul deklariert sind, das die Subroutine enthält).

Funktionen und Unterprogramme werden kollektiv als Prozeduren bezeichnet . (Im Folgenden wird das Verb verwenden „call“ als Synonym für „aufzurufen“ , auch wenn die Verfahren technisch sein call ed sind subroutine s, während die function S als rechte Seite der Zuweisung angezeigt oder in Ausdrücken.)

Funktionssyntax

Funktionen können mit verschiedenen Arten von Syntax geschrieben werden

function name()
  integer name
  name = 42
end function
integer function name()
  name = 42
end function
function name() result(res)
  integer res
  res = 42
end function

Funktionen geben Werte über ein Funktionsergebnis zurück . Wenn die Funktionsanweisung keine result , hat das result der Funktion denselben Namen wie die Funktion. Mit result das result der Funktion das result . In jedem der ersten beiden obigen Beispiele wird das Funktionsergebnis durch den name . im dritten durch res .

Das Funktionsergebnis muss während der Ausführung der Funktion definiert werden.

Funktionen erlauben die Verwendung einiger spezieller Präfixe.

Reine Funktion bedeutet, dass diese Funktion keine Nebenwirkung hat:

pure real function square(x)
  real, intent(in) :: x
  square = x * x
end function

Die Elementfunktion ist als Skalaroperator definiert, sie kann jedoch mit array als aktuellem Argument aufgerufen werden. In diesem Fall wird die Funktion elementweise angewendet. Wenn nicht das impure Präfix (eingeführt in Fortran 2008) angegeben wird, ist eine Elementfunktion ebenfalls eine reine Funktion.

elemental real function square(x)
  real, intent(in) :: x
  square = x * x
end function

Rückgabeanweisung

Die return Anweisung kann zum Beenden von Funktion und Unterprogramm verwendet werden. Im Gegensatz zu vielen anderen Programmiersprachen wird der Rückgabewert nicht festgelegt.

real function f(x)
  real, intent(in) :: x
  integer :: i

  f = x

  do i = 1, 10

    f = sqrt(f) - 1.0

    if (f < 0) then
      f = -1000.
      return
    end if

  end do
end function

Diese Funktion führt eine iterative Berechnung aus. Wenn der Wert von f negativ wird, gibt die Funktion den Wert -1000 zurück.

Rekursive Prozeduren

In Fortran müssen Funktionen und Unterprogramme explizit als rekursiv deklariert werden , wenn sie sich direkt oder indirekt erneut aufrufen möchten. Eine rekursive Implementierung der Fibonacci-Serie könnte also folgendermaßen aussehen:

recursive function fibonacci(term) result(fibo)
  integer, intent(in) :: term
  integer :: fibo

  if (term <= 1) then
    fibo = 1
  else
    fibo = fibonacci(term-1) + fibonacci(term-2)
  end if
  
end function fibonacci

Ein anderes Beispiel ist erlaubt, Fakultät zu berechnen:

recursive function factorial(n)  result(f)
  integer :: f
  integer, intent(in) :: n
  
  if(n == 0) then
    f = 1
  else
    f = n * f(n-1)
  end if
end function factorial

Damit eine Funktion sich selbst rekursiv referenzieren kann, muss ihre Definition das result . Es ist nicht möglich, dass eine Funktion sowohl recursive als auch elemental .

Die Absicht von Dummy-Argumenten

Das intent Attribut eines Dummy-Arguments in einer Subroutine oder Funktion gibt die beabsichtigte Verwendung an. Die Syntax ist entweder eine von

intent(IN)
intent(OUT)
intent(INOUT)

Betrachten Sie zum Beispiel diese Funktion:

real function f(x)
  real, intent(IN) :: x

  f = x*x
end function

Der intent(IN) gibt an, dass das (Nichtzeiger-) Dummy-Argument x während der gesamten Funktion oder ihrer Initialisierung niemals definiert werden oder undefiniert werden darf. Wenn ein Pointer-Dummy-Argument die Attributintent intent(IN) , gilt dies für seine Zuordnung.

intent(OUT) für ein Nicht-Zeiger-Dummy-Argument bedeutet, dass das Dummy-Argument beim Aufruf des Unterprogramms (mit Ausnahme von Komponenten eines abgeleiteten Typs mit Standardinitialisierung) undefiniert wird und während der Ausführung festgelegt wird. Das als Dummy-Argument übergebene tatsächliche Argument muss definierbar sein: Das Übergeben einer benannten Konstante oder eines Literalkonstanten oder eines Ausdrucks ist nicht zulässig.

Ähnlich wie zuvor wird der Zuordnungsstatus des Zeigers undefiniert, wenn ein Zeiger-Dummy-Argument intent(OUT) . Das eigentliche Argument muss hier eine Zeigervariable sein.

intent(INOUT) gibt an, dass das tatsächliche Argument definierbar ist und sich sowohl für die Übergabe als auch für die Rückgabe von Daten aus der Prozedur eignet.

Schließlich kann ein Dummy-Argument ohne das intent Attribut sein. Ein solches Dummy-Argument wird durch das tatsächlich übergebene Argument eingeschränkt.

Zum Beispiel betrachten

integer :: i = 0
call sub(i, .TRUE.)
call sub(1, .FALSE.)

end

subroutine sub(i, update)
  integer i
  logical, intent(in) :: update
  if (update) i = i+1
end subroutine

Das Argument i kann kein intent Attribut haben, das beide Unterprogrammaufrufe des Hauptprogramms zulässt.

Prozedur referenzieren

Damit eine Funktion oder ein Unterprogramm nützlich ist, muss darauf verwiesen werden. Ein Unterprogramm wird in einer referenzierten call - Anweisung

call sub(...)

und eine Funktion innerhalb eines Ausdrucks. Im Gegensatz zu vielen anderen Sprachen bildet ein Ausdruck keine vollständige Anweisung. Daher wird eine Funktionsreferenz häufig in einer Zuweisungsanweisung gesehen oder auf andere Weise verwendet:

x = func(...)
y = 1 + 2*func(...)

Es gibt drei Möglichkeiten, eine referenzierte Prozedur festzulegen:

  • als Name einer Prozedur oder eines Prozedurzeigers
  • eine Prozedurkomponente eines abgeleiteten Typobjekts
  • ein typgebundener Prozedurbindungsname

Der erste kann als gesehen werden

procedure(), pointer :: sub_ptr=>sub
call sub()   ! With no argument list the parentheses are optional
call sub_ptr()
end

subroutine sub()
end subroutine

und die letzten beiden als

module mod
  type t
    procedure(sub), pointer, nopass :: sub_ptr=>sub
  contains
    procedure, nopass :: sub
  end type

contains

  subroutine sub()
  end subroutine

end module

use mod
type(t) x
call x%sub_ptr()   ! Procedure component
call x%sub()       ! Binding name

end

Für eine Prozedur mit Dummy-Argumenten erfordert die Referenz entsprechende tatsächliche Argumente, obwohl optionale Dummy-Argumente möglicherweise nicht angegeben werden.

Betrachten Sie die Subroutine

subroutine sub(a, b, c)
  integer a, b
  integer, optional :: c
end subroutine

Darauf kann auf zwei Arten verwiesen werden

call sub(1, 2, 3)   ! Passing to the optional dummy c
call sub(1, 2)      ! Not passing to the optional dummy c

Dies ist die sogenannte Positionsreferenzierung : Die eigentlichen Argumente werden basierend auf der Position in den Argumentlisten zugeordnet. Hier ist der Dummy a mit 1 , b mit 2 und c (wenn angegeben) mit 3 verknüpft.

Alternativ kann die Schlüsselwortreferenzierung verwendet werden, wenn für die Prozedur eine explizite Schnittstelle verfügbar ist

call sub(a=1, b=2, c=3)
call sub(a=1, b=2)

das ist das gleiche wie oben.

Bei Schlüsselwörtern können die tatsächlichen Argumente jedoch in beliebiger Reihenfolge angeboten werden

call sub(b=2, c=3, a=1)
call sub(b=2, a=1)

Positions- und Schlüsselwortreferenzierung können beide verwendet werden

call sub(1, c=3, b=2)

solange ein Schlüsselwort für jedes Argument angegeben wird, das dem ersten Auftreten eines Schlüsselworts folgt

call sub(b=2, 1, 3)  ! Not valid: all keywords must be specified

Der Wert der Schlüsselwortreferenzierung ist besonders ausgeprägt, wenn es mehrere optionale Dummy-Argumente gibt, wie unten gezeigt, wenn in der obigen Subroutinen-Definition auch b optional war

call sub(1, c=3)  ! Optional b is not passed

Die Argumentlisten für typgebundene Prozeduren oder Komponentenprozedurzeiger mit einem übergebenen Argument werden separat betrachtet.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow