C++ Unendlich-Schleifen - Wie gut sind andere Compiler?



  • Hallo zusammen,

    es gibt ja unterschiedliche Variante eine Unendlich-Schleife zu formulieren.

    for(;;){
      // tbd
    }
    
    while(true) {
      // tbd
    }
    
    do {
      // tbd
    } while(true);
    

    Zu mir hieß es während meines Studiuems (in der Mikrocontoller-Vorlesung), dass die for Variante zu bevorzugen ist (=beste Übersetzung nach Assembler).
    Ein paar Jahre später habe ich das mal auf den Prüfstand gestellt.

    Mit Hilfe von Microsoft Visual Studio 2013 und Debug-Konfiguration bleibt die Aussage weiterhin gültig. Unter Release werden alle drei Variante zu einer jmp Anweisung optimiert.

    Frage: Erkennen das auch andere Compiler-Hersteller?

    ---------------------------
    Der Vollständigkeit hier noch der generierte Assemblercode (unter VS2013 & Debug):
    for

    0034139E  jmp         main+1Eh (034139Eh)
    

    while

    while (true) {
    003413A0  mov         eax,1  
    003413A5  test        eax,eax  
    003413A7  je          main+2Bh (03413ABh)  
    
      }
    003413A9  jmp         main+20h (03413A0h)
    

    do-while

    003413AB  mov         eax,1  
    003413B0  test        eax,eax  
    003413B2  jne         main+2Bh (03413ABh)
    


  • So Messungen ergeben nur Sinn, wenn die Compileroptimierungen an sind.
    IOch schätze, dann sind alle Varianten gleich, oder?



  • volkard schrieb:

    ... Ich schätze, dann sind alle Varianten gleich, oder?

    jb2603 schrieb:

    ... Unter Release werden alle drei Variante zu einer jmp Anweisung optimiert.

    Ja. Kann den davon ausgegangen werden, das andere Compiler (Clang, Gcc...) diese Optimierungen auch durchführen?


  • Mod

    Ohne zu testen: Natürlich werden sie das. Das ist eine derart triviale Optimierung, das lohnt nicht die Mühe des Ausprobierens, um es zu bestätigen.



  • Mir war langweilig: http://goo.gl/gKBG85
    Wohlgemerkt, das ist GCC ohne Optimierungen.



  • jb2603 schrieb:

    Zu mir hieß es während meines Studiuems (in der Mikrocontoller-Vorlesung), dass die for Variante zu bevorzugen ist (=beste Übersetzung nach Assembler).

    ernsthaft?



  • Ich hab immer sozusagen "in die Zukunft" gepr0ggert, also selbst wenn in diesem oder nächsten Jahr der Compiler die Optimierung noch nicht kann, weil sie trivial ist, doch wird er sie bald können. Ich fahre gut damit.

    for(;;) zu bevorzugen empfehle ich auch. Aber überhaupt gar nicht wegen der Geschwindigkeit, sondern weil es ein sehr übliches C++-Idiom ist. Es nicht zu nehmen, würde sagen, daß ich C++ erst seit ein paar Jahren betreiben würde oder keine Foren lesen oder an schlechten Büchern verhaftet wäre oder so.


  • Mod

    jb2603 schrieb:

    Zu mir hieß es während meines Studiuems (in der Mikrocontoller-Vorlesung), dass die for Variante zu bevorzugen ist (=beste Übersetzung nach Assembler).

    Eine Assemblernahe Übersetzung wäre eigentlich

    Label:
    goto Label;
    

    oder andere Sprungvarianten
    (oder eben

    Label:
     __asm
       {
          jmp Label;
       }
    

    )
    ..wirkt auf mich irgendwie transparenter 🤡



  • for(;;)
    

    wird von vielen gerne verwendet, weil man an der Form sofort sieht, dass hier eine endlos-schleife gemeint ist.
    Ich finde aber sowohl den missbrauch der eigentlich fuer reichweiten gedachten for-schleife als auch das doppel-semicolon haesslich, weswegen ich zu while (true) greife.


  • Mod

    nachtfeuer schrieb:

    jb2603 schrieb:

    Zu mir hieß es während meines Studiuems (in der Mikrocontoller-Vorlesung), dass die for Variante zu bevorzugen ist (=beste Übersetzung nach Assembler).

    Eine Assemblernahe Übersetzung wäre eigentlich

    Ich glaube, er meint, welche Variante den "besten" Maschinencode erzeugt, wenn man einen fünfzig Jahre alten Compiler ohne Optimierungen benutzt. Denn dann ist, wenn man die Schleifenkonstrukte als Compiler sehr, sehr wörtlich nimmt, ein while(true) immer noch mit einer echten Prüfung verbunden, ob true denn auch wirklich wahr ist. Ein for ganz ohne Abbruchbedingung hat hingegen nichts, was irgendwie geprüft werden könnte, das heißt ein bedingungsloser Rücksprung.



  • Marthog schrieb:

    for-schleife als auch das doppel-semicolon haesslich, weswegen ich zu while (true) greife.

    Deswegen haben wir Profis im zentralen Header alle

    #define ever ;;
    

    stehen.


  • Mod

    Grammatisch ginge auch ein anderes Schlüsselwort, wie

    fore
    

    oder

    foreverloop
    

    o.ä.
    aber als als C-Programmierer fühlt man sich ohne Sonderzeicheneinsatz unwohl...



  • jb2603 schrieb:

    Ja. Kann den davon ausgegangen werden, das andere Compiler (Clang, Gcc...) diese Optimierungen auch durchführen?

    Du kannst davon ausgehen dass einige aktuelle Compiler eine leere Endlosschleife sogar ganz entfernen.
    (Was sie auch dürfen, weil leere Endlosschleifen "gegen die Regeln" sind.)

    Und natürlich kannst du auch davon ausgehen dass, falls du etwas mit beobachtbarem Effekt in die Schleife reinpackst, womit das Programm dann Regelkonform ist und der Compiler die Schleife nicht mehr ganz wegoptimieren darf, sämtliche aktuellen Compiler schlau genug sind die drei verschiedenen Varianten zu identischem oder zumindest equivalentem Code zu übersetzen.



  • am einfachsten ist wenn du es mit dem gewuenschten compiler selbst ausprobierst:

    https://gcc.godbolt.org/

    hustbaer schrieb:

    Du kannst davon ausgehen dass einige aktuelle Compiler eine leere Endlosschleife sogar ganz entfernen.
    (Was sie auch dürfen, weil leere Endlosschleifen "gegen die Regeln" sind.)

    kannst du bitte erklaeren gegen welche regel das ist, bzw darauf referenzieren?



  • Ich denke ich habe in den letzten 5++ Jahren programmieren genau 0 Endlosschleifen gebraucht. Wozu braucht ihr das?



  • MahlErnsd schrieb:

    Ich denke ich habe in den letzten 5++ Jahren programmieren genau 0 Endlosschleifen gebraucht. Wozu braucht ihr das?

    Vor 15 Jahren war ich der Meinung, daß sie manchmal leichter zu lesen sind.
    http://www.tbi.univie.ac.at/~pmg/tutorials/tmp/vcppk/html/nimmspiel__darf_man_endlosschleifen_benutzen.html



  • MahlErnsd schrieb:

    Ich denke ich habe in den letzten 5++ Jahren programmieren genau 0 Endlosschleifen gebraucht. Wozu braucht ihr das?

    Ich verwende haeufig endlosschleife + early return.

    Wenn man z.B. eine mit Komma unterteilte Liste parsen will:
    while (komma) geht nicht, denn es steht ja keins am anfang.
    do ... while (komma) geht auch nicht, da die Liste auch leer sein kann. Eine extra if-befindung dafuer ist sinnlos.
    Irgendein boolean, das speichert, ob zuletzt ein Komma gelesen wurde, ist ziemlich witzlos.
    Als einzige gute Moeglichkeit bleibt endlosschleife und early return.

    Insgesamt finde ich endlosschleifen deutlich wichtiger, als do ... while


  • Mod

    rapso schrieb:

    hustbaer schrieb:

    Du kannst davon ausgehen dass einige aktuelle Compiler eine leere Endlosschleife sogar ganz entfernen.
    (Was sie auch dürfen, weil leere Endlosschleifen "gegen die Regeln" sind.)

    kannst du bitte erklaeren gegen welche regel das ist, bzw darauf referenzieren?

    §1.10, 24 in C++11: schrieb:

    The implementation may assume that any thread will eventually do one of the following:
    — terminate,
    — make a call to a library I/O function,
    — access or modify a volatile object, or
    — perform a synchronization operation or an atomic operation.

    [ Note: This is intended to allow compiler transformations such as removal of empty loops, even when
    termination cannot be proven. — end note ]



  • Marthog schrieb:

    MahlErnsd schrieb:

    Ich denke ich habe in den letzten 5++ Jahren programmieren genau 0 Endlosschleifen gebraucht. Wozu braucht ihr das?

    Ich verwende haeufig endlosschleife + early return.

    Wenn man z.B. eine mit Komma unterteilte Liste parsen will:
    while (komma) geht nicht, denn es steht ja keins am anfang.
    do ... while (komma) geht auch nicht, da die Liste auch leer sein kann. Eine extra if-befindung dafuer ist sinnlos.
    Irgendein boolean, das speichert, ob zuletzt ein Komma gelesen wurde, ist ziemlich witzlos.
    Als einzige gute Moeglichkeit bleibt endlosschleife und early return.

    Ich nehme an, du parst nichts unendlich großes, also wird im Schleifenkopf geprüft, ob du schon am Ende bist, das geht auch bei leeren Containern. Und return bei gefunden geht ja trotzdem. Das wird nicht mehr Code als die Endlosschleife, wahrscheinlich sogar weniger, weil du ja auch prüfen musst, ob du am Ende bist.



  • Nathan schrieb:

    Mir war langweilig: http://goo.gl/gKBG85
    Wohlgemerkt, das ist GCC ohne Optimierungen.

    Wusste gar nicht, dass es sowas gibt, danke Dir.

    Danke für Eure Meinungen und Kommentare. 🙂


Anmelden zum Antworten