Makro Loop



  • 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.


  • Mod

    @Pikkolini sagte in Makro Loop:

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

    Ärgerlich, dass die Compilerparameter zur Ausgabe des MSVC Präprozessors auf godbolt nicht zu funktionieren scheinen. Wenn sich da jemand auskennt, wäre das sehr hilfreich. Ansonsten könnte mal @Pikkolini bei sich probieren, was heraus kommt. Beim MSVC müsste das /E sein statt -E, weil Windows...



  • @SeppJ sagte in Makro Loop:

    Ärgerlich, dass die Compilerparameter zur Ausgabe des MSVC Präprozessors auf godbolt nicht zu funktionieren scheinen.

    Wie kommst Du darauf? sowohl -E als auch /E funktionert. Klick im Compilerfenster in godbolt unten auf "Output".


  • Mod

    @Swordfish sagte in Makro Loop:

    @SeppJ sagte in Makro Loop:

    Ärgerlich, dass die Compilerparameter zur Ausgabe des MSVC Präprozessors auf godbolt nicht zu funktionieren scheinen.

    Wie kommst Du darauf? sowohl -E als auch /E funktionert. Klick im Compilerfenster in godbolt unten auf "Output".

    Ahh! Danke.

    MSVC sagt:

    if (index, variableName, otherVariableName, latitude, longitude > 0) [...]
    

    [...]
    <source>(1326): warning C4003: not enough actual parameters for macro 'IF_BODY'

    Hmm. Kann MSVC keine Variadic Macros? Angeblich doch, aber scheint nicht zu funktionieren. Mir ist es aber gerade zu sehr Freitagabend, um das noch genauer zu analysieren. Sorry 😃



  • @SeppJ sagte in Makro Loop:

    Variadic Macros

    Das ist doch ein C99-Dings? Da kann schon sein daß er's nicht kann. (oder dabei zumindest rumzickt). Wär' aber eher ne Frage/Bugreport an die Boost Menschen als hier.



  • Interessant, scheint ein Bug von MSVC zu sein:
    https://stackoverflow.com/questions/55883451/nested-macro-with-variadic-arguments-does-compile-in-gcc-but-not-in-msvc

    Jetzt stellt sich nur noch die Frage, ob man diesen Bug irgendwie umgehen kann 🤔



  • @Pikkolini
    Eine Frage. Du willst also in einem Quellcode alle Arrays auflösen s.d. am Ende anstatt Arrays nur noch Variablen im Code stehen. Was machst du aber in den folgenden Fällen?

    int variableName[5];
    
    // Fall 1
    variableName[0] = 1;
    variableName[1] = 2;
    variableName[2] = 3;
    // Fall 2
    for (int i = 0; i < 3; i++)
    	variableName[(i * 2) % 5] = i;	
    // Fall 3
    int* P = &variableName[0];
    for (int i = 0; i < 3; i++)
    {
    	*P = i;
    	P++;
    }
    // Fall 4
    int Sum = CalculateSum(variableName);
    

    Ich würde hier nicht mit dem Präprozessor herangehen, da mir dieser nicht mächtig genug erscheint, sondern ein Python Skript probieren, welches sich folgermaßen aufrufen liese:

    DisolveArrays.py -in:ProjectFile -out:ProjectFile
    

    Eine rudimentäre Lösung sähe so aus:

    import re
    
    try:
        InFile = open("Test.cpp", "r")
    except:
        print("\nFehler! Konnte Eingabedatei nicht einlesen!")
        quit(0)
    try:
        OutFile = open("Test_Simulink.cpp", "w")
    except:
        print("\nFehler! Konnte Ausgabedatei nicht öffnen!")
        quit(0)
    
    for Line in InFile:
        x = re.search("(\w+) (\w+)[(\d+)];", Line)
        if (x):
            print("")
            print("Array gefunden: " + Line)
            print("Typ: " + x.group(1))
            print("Name: " + x.group(2))
            print("Größe: " + x.group(3))
            for i in range(int(x.group(3))):
                OutFile.write(x.group(1) + " " + x.group(2) + str(i) + ";\n")
        else:
            OutFile.write(Line)
    

    Test.cpp

    int a[10];
    objectType variableName[5];
    
    int main(int argc, char** argv)
    {
    	printf("Hallo Welt!\n");
    }
    

    Das Ganze müsste man natürlich noch für die besagten Fälle weiterentwickeln.



  • Alle Fälle sind kein Problem, aber Fall 2 und 3 treten sowieso nicht auf und Fall 4 in anderer Form (bei Fall 3 sei angemerkt, dass auf der Targethardware Variablen in structs hintereinander im Speicher liegen, und bei mir ist alles in structs gepackt). Ich sehe nicht wo das Problem liegen soll.
    Python war auch mein erster Gedanke, aber habe es für besser befunden keine weitere Komplikationen in die build chain einzubauen.

    P.S. Die Lösung meines Problems findet ihr im Stackoverflow thread.


Anmelden zum Antworten