Hier ist eine typische Verwendung von Funktionszeigern in C. Ich möchte etwas Ähnliches in Fortran tun. Ich habe einige Ideen, aber ich würde gerne wissen, ob es einen kanonischen Weg gibt, dies zu tun.
Die vom Benutzer übergebenen Funktionszeiger und Kontexte werden gespeichert und später aufgerufen.
typedef PetscErrorCode (*TSIFunction)(TS,PetscReal,Vec,Vec,Vec,void*);
PetscErrorCode TSSetIFunction(TS ts,Vec res,TSIFunction f,void *ctx);
Die Funktion des Benutzers wird zu verschiedenen späteren Zeitpunkten unter Verwendung seines Kontexts zurückgerufen.
In PETSc verwenden sie auch stark String -> Funktionszeigertabellen. Alles ist ein Plugin, so dass der Benutzer seine eigenen Implementierungen registrieren kann und sie erstklassig sind.
#define PCGAMG "gamg"
PCRegisterDynamic(PCGAMG ,path,"PCCreate_GAMG",PCCreate_GAMG);
Dadurch wird die Erstellungsroutine in einer "FList" registriert, und PCSetFromOptions () bietet die Möglichkeit, diese Methode im Vergleich zu anderen Optionen auszuwählen. Wenn das System das dynamische Laden unterstützt, können Sie die Abhängigkeit zur Kompilierungszeit vom PCCreate_GAMG-Symbol überspringen und einfach NULL übergeben. Anschließend wird das Symbol zur Laufzeit in der gemeinsam genutzten Bibliothek nachgeschlagen.
Beachten Sie, dass dies ein Schritt über eine "Fabrik" hinaus eine Umkehrung des Steuergeräts ist, ähnlich dem, was Martin Fowler "Service Locator" nennt.
Hinweis: Dies kam in meiner privaten Korrespondenz mit Jed Brown zum Ausdruck, in der er mir diese Frage stellte. Ich beschloss, es auszulagern und zu sehen, welche Antworten die Leute finden können.
Ich vermute, dass Ihre Frage eine PETSc-spezifische Sprache enthält (mit der ich nicht vertraut bin), daher kann es hier zu Falten kommen, die ich nicht ganz verstehe, aber vielleicht ist dies dennoch hilfreich, um Sie zu erreichen gestartet.
Grundsätzlich müssen Sie die Schnittstelle für die Prozedur definieren und dann einen Zeiger auf eine Funktion übergeben, die dieser Schnittstelle folgt. Der folgende Code zeigt ein Beispiel. Erstens gibt es ein Modul, das die Schnittstelle definiert und ein kurzes Beispiel für einen Codeabschnitt zeigt, der die vom Benutzer bereitgestellte Routine ausführt, die dieser Schnittstelle folgt. Als nächstes folgt ein Programm, das zeigt, wie der Benutzer dieses Modul verwenden und die auszuführende Funktion definieren würde.
quelle
PROCEDURE(function_template), POINTER :: func
intern zu speichern .void*
, muss der Benutzer selbst Schnittstellen für Bibliotheksfunktionen schreiben. Wenn Sie die Bibliothek in C implementieren, reicht dies aus. Wenn Sie jedoch in Fortran implementieren, müssen Sie sicherstellen, dass der Compiler die "Dummy" -SCHNITTSTELLE der Bibliothek niemals gleichzeitig mit der SCHNITTSTELLE des Benutzers sieht.void*
in Fortran ist einetransfer
Methode. Sehen Sie hier für ein Beispiel der Nutzung. Die anderen 3 Ansätze neben dertransfer
Methode sind "Arbeitsarrays", "spezifischer abgeleiteter Typ anstelle vonvoid *
" und verwenden modullokale Modulvariablen.transfer
einem Unsinnstyp (character (len=1), allocatable
) herumspielen muss, um die Funktion aufzurufen.