Preprocessor Schleife mit definierter Anzahl von Durchläufen



  • Wie kann man mit dem Preprocesor erreichen, dass ein bestimmter Ausdruck eine als Parameter übergebene Anzahl n mal in den zu kompilierenden Code eingefügt wird?

    #define loop(n,expr) irgendeinmacrobody
    

    soll sich so auflösen:

    expr;expr;expr...(n mal)

    Geht das überhaupt, wo doch kein #if, welches einen Schleifenzähler abfragen könnte in das #define eingebaut werden kann?


  • Mod

    Das geht mit viel Schreibarbeit bei der Definition der Präprozessormakros (oder indem man sich die nötigen Makros mit einem Computerprogramm generiert 🙂 ). Oder, damit man das nicht machen muss, eine fertige Präprozessorbibliothek benutzen. Zum Beispiel Boost.Preprocessor. Ist zwar eigentlich für C++, aber der Präprozessorteil sollte auch in C funktionieren.

    Wozu willst du das überhaupt? Jetzt sag nicht "Um Code "ABC" N-Mal zu wiederholen", das wissen wir schon. Was ist das eigentliche Ziel?



  • Sozusagen das totale Loop Unrolling 😉
    Beim Loop Unrolling will man ja sozusagen den Prozentsatz der Kernanweisungen im Verhältnis zu den Anweisung für die Schleifensteuerung steigern.
    Allerdings wird damit nicht berücksichtigt, dass mit einer vollständig entrollten Schleife auch sich mit jedem Schleifendurchlauf ändernde Variablen direkt als Konstanten in den Programmcode übernommen werden können. Das Makro soll sozusagen die Anzahl der Wiederholungen und einen Ausdruck mit den Berechnungsvorschriften für die Konstanten und den zu wiederholenden Befehlen übergeben bekommen.

    Beispiel:

    for (i=0; i<10; i++){printf("\n%d",i);}
    

    soll eben nicht zu

    printf("\n%d",0);
    printf("\n%d",1);
    printf("\n%d",2);
    

    usw.

    werden, sondern zu

    printf("\n""0");
    printf("\n""1");
    printf("\n""2");
    

    usw.

    und das wird durch automatisches Loop Unrolling einfach nicht bewerkstelligt.


  • Mod

    Ok, das ist ein nachvollziehbares Ziel, deine Methode dafür sollte auch passen. Reicht dir der gegebene Ratschlag, eine Präprozessorbibliothek zu nutzen?



  • Also, ich will zumindest nicht meckern, bevor ichs ausprobiert habe. Was ist denn eine gute Einsteiger Preprocessor Bibliothek? Die genannte Boost?
    Oder gibt es simplere Alternativen?


  • Mod

    Die von Boost ist sicher eine gute Wahl. Aber wenn du schon gezielt nach etwas einfachem fragst, dann ist das alles wohl eher nichts für dich. Auf einfache Weise komplexe Aufgaben mit dem Präprozessor zu erledigen geht nämlich nicht.



  • Wie gross ist n? Unter 32 kann man das auch gut selber schreiben.


  • Mod

    unbooost schrieb:

    Wie gross ist n? Unter 32 kann man das auch gut selber schreiben.

    Noch als Nachtrag, wie das an sich selber zu schreiben ist: Dir Grundidee ist folgende:

    #define REPEAT_5(foo) foo REPEAT_4(foo)
    #define REPEAT_4(foo) foo REPEAT_3(foo)
    #define REPEAT_3(foo) foo REPEAT_2(foo)
    #define REPEAT_2(foo) foo REPEAT_1(foo)
    #define REPEAT_1(foo) foo
    
    #define REPEAT(foo, N) REPEAT_##N (foo)
    
    REPEAT(bla!, 3)
    

    Soweit so unübersichtlich. Noch komplizierter wird es, wenn man auch noch berücksichtigen möchte, dass in den Ausdrücken Kommas vorkommen können. Und wahrscheinlich noch ein paar andere Sachen, die ich gerade vergesse. Ich denke es ist klar geworden, wieso man das nicht von Hand schreiben möchte.



  • SeppJ schrieb:

    Ich denke es ist klar geworden, wieso man das nicht von Hand schreiben möchte.

    Ich denke, es ist klar geworden, dass du damit kaum Erfahrung hast.

    #define COMPILE_TIME_LOOP_5() LOOP_ACTION(5) COMPILE_TIME_LOOP_4() 
    #define COMPILE_TIME_LOOP_4() LOOP_ACTION(4) COMPILE_TIME_LOOP_3() 
    #define COMPILE_TIME_LOOP_3() LOOP_ACTION(3) COMPILE_TIME_LOOP_2() 
    #define COMPILE_TIME_LOOP_2() LOOP_ACTION(2) COMPILE_TIME_LOOP_1() 
    #define COMPILE_TIME_LOOP_1() LOOP_ACTION(1)
    
    #define COMPILE_TIME_LOOP(n) COMPILE_TIME_LOOP_ ## n()
    
    int main() {
    #define LOOP_ACTION(i) printf("\n" #i);
      COMPILE_TIME_LOOP(5)
    #undef LOOP_ACTION
    }
    


  • Beziehunsweise so, wenn du wie forwärts durchlaufen willst:

    #define COMPILE_TIME_LOOP_5() COMPILE_TIME_LOOP_4() LOOP_ACTION(4)
    #define COMPILE_TIME_LOOP_4() COMPILE_TIME_LOOP_3() LOOP_ACTION(3)
    #define COMPILE_TIME_LOOP_3() COMPILE_TIME_LOOP_2() LOOP_ACTION(2)
    #define COMPILE_TIME_LOOP_2() COMPILE_TIME_LOOP_1() LOOP_ACTION(1)
    #define COMPILE_TIME_LOOP_1()                       LOOP_ACTION(0)
    

  • Mod

    unbooost schrieb:

    SeppJ schrieb:

    Ich denke es ist klar geworden, wieso man das nicht von Hand schreiben möchte.

    Ich denke, es ist klar geworden, dass du damit kaum Erfahrung hast.

    Ja, denn ich zeige dem absoluten Anfänger nicht gleich die komplizierteste Variante, sondern etwas, das man auch auf Anhieb verstehen könnte. Ich weiß auch nicht, was ich mir dabei bloß gedacht habe. 🙄


  • Mod

    Übrigens ginge das was du machst richtig in dieser Art:

    #define REPEAT_5(foo) foo(5) REPEAT_4(foo)
    #define REPEAT_4(foo) foo(4) REPEAT_3(foo)
    #define REPEAT_3(foo) foo(3) REPEAT_2(foo)
    #define REPEAT_2(foo) foo(2) REPEAT_1(foo)
    #define REPEAT_1(foo) foo(1)
    
    #define REPEAT(foo, N) REPEAT_##N (foo)
    
    #define MY_LOOP_ACTION(N) printf("\n" #N)
    
    REPEAT(MY_LOOP_ACTION, 3)
    

    So muss der Benutzer nämlich nicht deine Implementierungsdetails (LOOP_ACTION) kennen.



  • Und jetzt bitte für größere Anzahlen mit rekursiven #includes.



  • Die #defines in dieser Art und Weise zu verwenden unterliegt natürlich immernoch starken Beschränkungen, wie z.B. dass die maximale Anzahl an Wiederholungen der Anzahl der #defines entspricht. Ist auf jeden Fall ne Alternative, die ich mir merken werde. Allerdings versuche ich mich dann doch erstmal mal mit der Boost, weil ich dann gleich in voller Allgemeinheit arbeiten kann.


  • Mod

    MC schrieb:

    Die #defines in dieser Art und Weise zu verwenden unterliegt natürlich immernoch starken Beschränkungen, wie z.B. dass die maximale Anzahl an Wiederholungen der Anzahl der #defines entspricht. Ist auf jeden Fall ne Alternative, die ich mir merken werde. Allerdings versuche ich mich dann doch erstmal mal mit der Boost, weil ich dann gleich in voller Allgemeinheit arbeiten kann.

    Boost kocht auch nur mit Wasser. Die benutzen natürlich all die Tricks, die ich und andere hier nur am Rande erwähnt haben, ohne sie zu zeigen. Aber im Prinzip steckt da das gleiche hinter, nämlich Ausschreiben aller Möglichkeiten. Insbesondere heißt das, dass es ein Maximum für die Anzahl der Wiederholungen gibt. Näheres ist in der Dokumentation erklärt.

    volkard schrieb:

    Und jetzt bitte für größere Anzahlen mit rekursiven #includes.

    Nein, bitte nicht. Da verweise ich auf den Boost Quellcode. Sofern die das überhaupt benutzen.


Anmelden zum Antworten