Makro Loop



  • Hallo zusammen,

    ich bin leider in der misslichen Lage in Simulink C++ programmieren zu müssen.
    Da in Simulink leider keine Arrays möglich sind (weitere Ausführungen erspare ich mir erstmal) brauche ich ein Makro, was folgendes macht:

    objectType variableName[5];
    // zu:
    objectType variableName00;
    objectType variableName01;
    objectType variableName02;
    objectType variableName03;
    objectType variableName04;
    

    Wie man den ## Operator in Makros benutzt etc. habe ich schon herausgefunden. Jedoch habe ich noch keine Lösung dafür gefunden, abhängig vom Argument den output des Makros zu ändern.
    Ist das überhaupt möglich? Oder gibt es vielleicht eine andere Lösung für das Problem?


  • Mod

    Kannst du Boost.Preprocessor einbinden?



  • Wenn es nur ein Header ist, ja. Wenn eine Lib dazu gehört ungerne.



  • Es ist eine header-only Library: Boost.Preprocessor -> Headers.

    Es reicht dann
    #include <boost/preprocessor.hpp>



  • Wieso sind in Simulink C++ keine Arrays möglich?
    Und wenn das so ist, würde mich eher wundern wenn sich da überhaupt irgendwas mit Boost inkludieren lässt.



  • Vielen Dank, ich werde mir BOOST_PP_REPEAT mal anschauen.

    @hustbaer sagte in Makro Loop:

    Wieso sind in Simulink C++ keine Arrays möglich?
    Und wenn das so ist, würde mich eher wundern wenn sich da überhaupt irgendwas mit Boost inkludieren lässt.

    Im normalen Programm kann ich normal C++ programmieren, das ist kein Problem. Sobald man jedoch über einen Bus was ausgeben möchte wirds kompliziert. Bei den Bussen ist man sehr eingeschränkt, was die Datenstruktur angeht. Wenn man dann auch noch diverse Toolboxen für diverse Targethardware benutzt will man sich die Kugel geben.
    Aber eine header-only library sollte funktionieren 🙂



  • Das Beispiel von Boost funktioniert für Deklarationen schonmal bestens:

    #include <boost/preprocessor/repetition/repeat.hpp>
    
    #define DECL(z, n, text) text ## n = n;
    
    BOOST_PP_REPEAT(5, DECL, int x)
    

    Jetzt möchte ich damit aber auch andere Konstrukte verwirklichen die mehr als das eine Argument text benötigen. Dem Makro, das ich BOOST_PP_REPEAT übergebe, in diesem Fall DECL kann aber maximal 3 Argumente annehmen. Wie kann ich das Makro erweitern, so dass ich z.B. 2 Textargumente, also insgesamt 4 Argumente übergeben kann?
    Da stehe ich leider aktuell was auf dem Schlauch.



  • #define ESC(...) __VA_ARGS__
    #define IF_BODY(n, var1, var2, var3) if (var1 > n) {var2##n = var3[n]}
    #define IF_QUERY(z, n, vars) IF_BODY(n, ESC vars)
    
    BOOST_PP_REPEAT(8, IF_QUERY, (test1, test2, test3))
    

    Ich bin aktuell soweit.
    Jedoch kompiliert das nicht, da IF_BODY nur 2 statt 4 Argumente bekommt. Anscheinend wird das ESC erst nach dem Makro Aufruf evaluiert. Wie kann man das lösen?



  • Habs

    #define ESC(...) __VA_ARGS__
    #define EXPAND_ARGS(X) X
    #define IF_BODY_(n, var1, var2, var3) if (var1 > n) {var2##n = var3[n]}
    #define IF_BODY(A, B) IF_BODY_(A, B)
    #define IF_QUERY(z, n, vars) IF_BODY(n, EXPAND_ARGS(ESC vars))
    
    BOOST_PP_REPEAT(8, IF_QUERY, (test1, test2, test3))
    

    Jetzt eine Erklärung warum genau das funktioniert wäre gut 😃


  • Mod

    @Pikkolini sagte in Makro Loop:

    Vielen Dank, ich werde mir BOOST_PP_REPEAT mal anschauen.

    @hustbaer sagte in Makro Loop:

    Wieso sind in Simulink C++ keine Arrays möglich?
    Und wenn das so ist, würde mich eher wundern wenn sich da überhaupt irgendwas mit Boost inkludieren lässt.

    Im normalen Programm kann ich normal C++ programmieren, das ist kein Problem. Sobald man jedoch über einen Bus was ausgeben möchte wirds kompliziert. Bei den Bussen ist man sehr eingeschränkt, was die Datenstruktur angeht.

    Das ist nicht nachvollziehbar. Arrays sind eine abstrakte syntaktische Hilfe, die auf niedrigeren Ebenen nicht mehr existieren. Was die Hardware deiner Maschine deshalb nicht zu jucken braucht, ob die Objekte im Source ueber ein Array aggregiert waren.



  • Der Code wird aber auf einer höheren Eben in der Toolchain ausgewertet. Da hängt ein riesen Rattenschwanz dran. Und dieser will sogennante nested buses (Arrays in structs) nunmal nicht haben.
    Gibt es irgendwo ein gutes Tutorial zu Boost Preprocessor? Die Referenz ist grauenhaft und auf Stackoverflow sind nur die erhabenen Macrometaprogrammierer unterwegs, die zwar wissen wie es funktionier ihr Wissen aber nicht mit unwürdigen teilen wollen.



  • @Columbo Vielleicht gibt's da irgend einen Parser der ein Subset von C parsen kann um daraus irgendwelche Message-Definitionen für die Gegenseite zu erstellen.



  • @Pikkolini Ich würde dir raten diverse PP-Magie zu vergessen und die paar Zeilen mit Hand rein zu schreiben.



  • @hustbaer sagte in Makro Loop:

    @Pikkolini Ich würde dir raten diverse PP-Magie zu vergessen und die paar Zeilen mit Hand rein zu schreiben.

    Das Problem ist, dass die Größe der Arrays zwar zur Compilezeit bekannt ist, sich aber jedes mal vorm Compilen ändern kann. Außerdem reden wir von mehreren Arrays mit Größen > 100
    Das ist dann leider nicht mal eben geändert.
    Oder kurz gesagt, die Lösung muss skalieren.



  • @Pikkolini: Durch was ändern sich die Arrays vor dem compilieren?
    Eventuell sollte man dort eingreifen, dass gleich das passende rausfällt (Falls es eine art Code-Generator ist)



  • Eine Frage habe ich noch. Wenn ich einem Macro ein Variablenname übergebe, wird der Wert der Variable evaluiert und dieser dem Macro übergeben. Wie schaffe ich es den Namen, nicht den Wert der Variable zu übergeben?



  • @Pikkolini sagte in Makro Loop:

    Wenn ich einem Macro ein Variablenname übergebe, wird der Wert der Variable evaluiert und dieser dem Macro übergeben.

    Nein.

    #define FOO(bar) bar
    
    int main()
    {
        int a{ 42 };
        FOO(a);
    }
    

    wird zu

    int main()
    {
        int a{ 42 };
        a;
    }
    


  • Hmm ich bekomme bei folgendem Code:

    # define ESC(...) __VA_ARGS__
    # define EXPAND_ARGS(X) X
    #define IF_BODY(n, condition, lhs, rhs, arg1, arg2) \
    if (condition > n) { \
        lhs##n.arg1 = rhs[n].arg1; \
        lhs##n.arg2 = rhs[n].arg2; \
    }
    # define IF_BODY_(A, B) IF_BODY(A, B)
    # define IF_QUERY(z, n, vars) IF_BODY_(n, EXPAND_ARGS(ESC vars))
    
    BOOST_PP_REPEAT(3, IF_QUERY, \
    		(variableName, otherVariableName, latitude, longitude))
    

    Den Fehler, dass variableName und Konsorten undeklarierte Bezeichner sind.


  • Mod

    Dann wird das wohl so stimmen. Jeder Compiler den ich kenne, kann auch irgendwie nur den Preprocessor laufen lassen, ohne danach eine Übersetzung zu versuchen. Z.B beim gcc mit dem Parameter -E. So kannst du sehen, was aus deinen Makros für Code erzeugt wird, und ob das valides C++ ist.

    In deinem Beispiel ist natürlich unmittelbar klar, dass variableName nicht definiert ist, weil es nirgendwo definiert wird. Daher nehme ich mal an, dass der Code Teil eines längeren Programms ist.



  • Interessanterweise hat nur der MSVC das Problem. Im GCC klappt es reibunglos. Siehe
    hier
    und
    hier

    @SeppJ sagte in Makro Loop:

    In deinem Beispiel ist natürlich unmittelbar klar, dass variableName nicht definiert ist, weil es nirgendwo definiert wird. Daher nehme ich mal an, dass der Code Teil eines längeren Programms ist.

    Hier sei zu beachten, die Fehlermeldung ist variableName ist nicht definiert. In dem Code sollte es aber gar kein variableName geben sondern nur ein variableName0.latitude etc.
    Soll heißen das Makro wird gar nicht richtig aufgelöst.


Anmelden zum Antworten