C++ Fortran wrapper



  • Bashar schrieb:

    Nein, das zweite Posting.

    Oh, das hatte ich gar nicht gesehen.

    Dann schauen wir mal wieder, was ich wieder alles zu lernen habe ...



  • Klaus82 schrieb:

    Bashar schrieb:

    Nein, das zweite Posting.

    Oh, das hatte ich gar nicht gesehen.

    Ich weiß, mein vorheriges Posting war auch eher als Hinweis darauf zu verstehen ... aber lassen wir das.



  • Also um auf diesen Gültigkeitsbereich einzugehen, vielleicht verstehe ich ein Teil des Problems richtig, was erstmal gar nichts mit Arrays & Co. zu tun hat.

    Ich arbeite in einer Funktion und erstelle darin eine Variable. Jetzt sollte es doch prinzipiell möglich sein, dass ich die Adresse dieser Variable als return -statement der Funktion ausgebe.

    Diese Adresse speichere ich dann in einem Pointer.

    Das Problem ist nun, dass in diesem Augenblick die Funktion beendet ist und damit alles ungültig wird, was darin initialisiert wurde.

    Damit zeigt der Pointer ... ja wohin eigentlich? Ist das nicht einfach ein Dangling Pointer? Oder ist das schlimmer, weil der Speicher nicht einfach nur angefordert und vergessen wurde wieder freizugeben, sondern regelrecht 'ungültig' ist?

    Gruß,
    -- Klaus.



  • Klaus82 schrieb:

    Ich arbeite in einer Funktion und erstelle darin eine Variable. Jetzt sollte es doch prinzipiell möglich sein, dass ich die Adresse dieser Variable als return -statement der Funktion ausgebe.

    Ja, das ist möglich. Zumindest prinzipiell.

    Damit zeigt der Pointer ... ja wohin eigentlich?

    Der zeigt dahin, wo er vorher hingezeigt hat. Aber da liegt nicht mehr dasselbe wie vorher ... vielleicht liegen da noch Überreste deines Objektes, vielleicht sogar unverändert. Vielleicht liegt da jetzt ein neues Objekt. Vielleicht Rücksprungadressen oder dergleichen. Vielleicht wurde der Speicher auch an das Betriebssystem zurückgegeben. Wer weiß?



  • Okay.

    Also kann der Inhalt der Funktion nicht über das return -statement stattfindetn.

    Kann ich da mit einer Mischung aus Pointer / Referenz und move-Semantik arbeiten? Ich übergebe einen Pointer an die Funktion und bewege dann den gewünschten Inhalt mittels move .

    Damit sollte der Inhalt in den Gültigkeitsbereich des Pointers / der Referenz übergehen und die überleben ja das Ende der Funktion.

    Sind da brauchbare Gedanken dabei?

    Gruß,
    -- Klaus.



  • Theoretisch schon, aber das ganze steht und fällt damit, was von der Fortran-Seite her möglich ist. Wenn Arrays so wie von dir gezeigt wie in C übergeben werden, kannst du das alles vergessen. Ist das überhaupt so? Probier das mal aus:

    #include <iostream>
    #include <vector>
    
    extern "C"{
        void show_array_(unsigned int* n, double* arr);
    }
    
    void show_array_(unsigned int* n, double* arr)
    {
        for (unsigned i = 0; i < *n; ++i)
          cout << arr[i] << '\n';
    }
    

    ?



  • Das funktioniert ohne Probleme. 🙂

    Gruß,
    -- Klaus.


  • Mod

    Bashar schrieb:

    Theoretisch schon, aber das ganze steht und fällt damit, was von der Fortran-Seite her möglich ist. Wenn Arrays so wie von dir gezeigt wie in C übergeben werden, kannst du das alles vergessen. Ist das überhaupt so?

    Ja, Fortran und C arbeiten zusammen, habe ich schon einmal gemacht. Aufpassen muss man vor allem bei 2 Dingen:
    1. in Fortran ist alles "by reference", aber auch nicht richtig, sondern über die selbe Krücke wie in C mittels Pointern. Man sieht es bloß nicht so leicht.
    2. Mehrdimensionale Arrays sind genau anders herum geordnet.



  • SeppJ schrieb:

    Ja, Fortran und C arbeiten zusammen, habe ich schon einmal gemacht. Aufpassen muss man vor allem bei 2 Dingen:
    1. in Fortran ist alles "by reference", aber auch nicht richtig, sondern über die selbe Krücke wie in C mittels Pointern. Man sieht es bloß nicht so leicht.
    2. Mehrdimensionale Arrays sind genau anders herum geordnet.

    OK, dann entfällt das Verändern der Größe. Das dürfte dann aber selbst in Fortran nicht gehen.

    Ich weiß nicht, ob man in C++ ein Array mit new anlegen kann, das man in Fortran deletet. Dann könntest du deinen Vektor zumindest *irgendwie* zurückbekommen.


  • Mod

    Bashar schrieb:

    Ich weiß nicht, ob man in C++ ein Array mit new anlegen kann, das man in Fortran deletet. Dann könntest du deinen Vektor zumindest *irgendwie* zurückbekommen.

    Wilde Idee: malloc/free müssten zu Fortran kompatibel sein, weil man einfach die C-Version statt dem Fortran-Äquivalent benutzen kann.

    Bei new ist das natürlich kritischer, da theoretisch nicht einmal new und free kompatibel sein müssen. Man könnte natürlich jeweils einen C-kompatiblen Wrapper um new und delete machen. edit: Hmm, man bekommt natürlich auf keine Weise die nötige Typeninformation von Fortran aus zum C++-Teil. Man müsste sich also doch auf malloc beschränken oder lauter Spezialisierungen für verschiedene Typen anbieten. Beides unbefriedigend 😞 .



  • Okay,
    ein Vorschlag zur Güte in 1. Näherung:

    Nach meinem bisherigen Verständnis der Problemstellung muss der Array wachsen. Es lässt sich allerdings schon auf der Seite von Fortran abschätzen was die maximale neue Länge sein wird, nämlich gerade das Doppelte.

    Also wäre der Fahrplan:

    Fortran gibt den Array vor.
    Fortran hängt einen Array gleicher Länge mit Nullen gefüllt dran.
    Fortran übergibt den Array doppelter Länge mittels des Wrappers an C++.
    C++ arbeitet und gibt den Array zurück.

    Das sollte doch in 1. Näherung das Problem des allokierten Speichers umgehen, oder?

    Gruß,
    -- Klaus.


  • Mod

    Denk nicht so sehr in Sprachen, sondern in Verantwortung. Du übergibst ein Objekt an eine Funktion, dadurch sollte aber niemals die Verantwortung für ein Objekt wechseln! (Außer die Funktion ist genau für diesen Zweck da, zum Beispiel der Konstruktor eines Smartpointers). Das heißt der Aufrufer ist und bleibt verantwortlich für Erzeugung und Zerstörung des Objekts und nutzt dazu die Mittel seiner Sprache. Muss die Funktion das Objekt verändern oder darauf zugreifen, so nutzt sie die Methoden des Objekts dafür (was, je nach Sprache, in der die "Klasse" des Objekts geschrieben wurde, auch durchaus freie Funktionen sein können).
    Das ist der Hintergedanke der Kapselung in der Objektorientierung. In dieser abstrakten Formulierung funktioniert das auch über Sprachgrenzen hinweg.

    P.S: Ja, dein Vorschlag sollte ok sein. Wenn ich dich richtig verstanden habe, verwaltet der Fortran-Teil deines Programms das Array (das Objekt) und ruft mit diesem Objekt eine in C++ geschriebene Funktion auf. Der C++-Code benutzt das Array aber nur, die Verantwortung bleibt aber beim Anwendungscode, also dem Fortranprogramm.



  • Puh,
    also die Aussage mit der Verantwortung habe ich noch nicht verstanden.

    Aber ich versuche mal das mit der Objektorientierung mit meinen eigenen Worten wiederzugeben:
    Bei der Planung des Codes muss überlegt werden, welche Aufgaben ein Objekt erfüllen soll und wie es verändert werden kann. Diese Funktionen müssen dann Methoden des Objekts selbst sein, die 'von-außen' nur noch aufgerufen werden.

    Beispiel vector : Für diesen ist vorgesehen, dass die Länge wächst, aus diesem Grund gibt es z.B. die Funktion push_back() .

    Gegenbeispiel array : Dies ist ein Feld konstanter Länge, d.h. wenn eine Funktion auf einmal Elemente anhängen möchte, dann tut die Funktion etwas, was nicht vorgesehen ist.
    Dann ist das allerdings nicht das Problem der Funktion, sondern ein schlechtes Design, weil array (als Objekt selbst) nicht die Methoden bereitstellt, die in der Funktion benötigt werden.

    SeppJ schrieb:

    [..] verwaltet der Fortran-Teil deines Programms das Array (das Objekt) und ruft mit diesem Objekt eine in C++ geschriebene Funktion auf. Der C++-Code benutzt das Array aber nur, die Verantwortung bleibt aber beim Anwendungscode, also dem Fortranprogramm.

    Wenn wir jetzt schon bei Wörten wie Designentscheidung sind, dann muss ich da nochmal in die Planungsphase und genau überlegen welche Aufgaben seitens welcher Programmiersprache übernommen werden.

    Gruß,
    -- Klaus.



  • Und überhaupt ist der gezeigte FORTRAN-Code kein klassischer FORTRAN-Standard mehr. FORTRAN ist älter als als C und noch einmal älter als C++.
    Will man mit auf OOP angepasstem FORTRAN arbeiten, nimmt man besser gleich C++ und braucht keinen wrapper. Ich jedenfalls war sehr froh, das
    gemischtsprachige Programmieren einmal ganz zu vergessen. Unter DOS kam man sogar kaum an Assembler vorbei.


Anmelden zum Antworten