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



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



  • MahlErnsd schrieb:

    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.

    void ParseNullTerminatedString(char const* s)
    {
        for (;;)
        {
            char const ch = *s++;
            switch (ch)
            {
            case ',':
                // ...
                break;
            case ' ':
                // ...
                break;
            // ...
            case 0:
                return;
            }
        }
    }
    

    Das mit while (*s) umzuschreiben ist natürlich möglich, aber mMn. schlecht, da es etwas trennt/aufbricht was eigentlich logisch zusammengehört.

    for (;;)
        {
            {
                lock_guard l(m_mutex);
                if (...)
                    break;
            }
    
            // Do stuff during which the mutex must NOT be locked
        }
    

    Hier kann man mit was mit boost::reverse_lock o.ä. basteln, aber ... naja, ist nicht jedermanns Sache. Und wo kein Boost müsste man es sich erst basteln. Kann man machen, geht aber auch so.
    Und natürlich kann man es mit manuellem lock/unlock auf nen unique_lock o.Ä. machen - nur das finde ich persönlich gänzlich furchtbar.

    Natürlich sehr subjektiv, aber meine aktuelle Präferenz:

    // geht nicht
        do
        {
            // ...
            bool c = ...;
        }
        while (c);
    
    // doof
        bool c;
        do
        {
            // ...
            c = ...;
        }
        while (c);
    
    // noch doofer
        bool c = true;
        while (c)
        {
            // ...
            c = ...;
        }
    
    // gut:
        for (;;)
        {
            // ...
            bool c = ...;
            if (!c)
                break;
        }
    


  • hustbaer schrieb:

    MahlErnsd schrieb:

    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.

    void ParseNullTerminatedString(char const* s)
    {
        for (;;)
        {
            char const ch = *s++;
            switch (ch)
            {
            case ',':
                // ...
                break;
            case ' ':
                // ...
                break;
            // ...
            case 0:
                return;
            }
        }
    }
    

    Irgendwie jetzt genau meine Antwort von oben. Und wie erwartet sogar kürzer.

    void ParseNullTerminatedStringWhile(char const* s)
    {
        while (char const ch = *s++)
        {
            switch (ch)
            {
            case ',':
                // ...
                break;
            case ' ':
                // ...
                break;
            // ...
            }
        }
    }
    

    hustbaer schrieb:

    for (;;)
        {
            {
                lock_guard l(m_mutex);
                if (...)
                    break;
            }
    
            // Do stuff during which the mutex must NOT be locked
        }
    

    Hier kann man mit was mit boost::reverse_lock o.ä. basteln, aber ... naja, ist nicht jedermanns Sache. Und wo kein Boost müsste man es sich erst basteln. Kann man machen, geht aber auch so.

    Nichts sagender Code der garkeine Abbruchbedingung enthält.
    Natürlich kann man Endlosschleifen verwenden, wenn man etwas programmiert was ewig laufen soll, z.B. eine Armbanduhr ohne OS. Aber bei 99% aller Schleifen loop man über irgendwas, was irgendwann zu Ende ist und ich weiß nicht, wieso man diese Bedingung irgendwo mitten in der Schleife verstecken soll.



  • MahlErnsd schrieb:

    Irgendwie jetzt genau meine Antwort von oben. Und wie erwartet sogar kürzer.

    Was ich jetzt nicht wirklich als Verbesserung empfinde.
    Und... was machst du wenn die Abbruchbedingung nicht zufällig "ist Null" ist?

    MahlErnsd schrieb:

    Nichts sagender Code der garkeine Abbruchbedingung enthält.

    Wenn der Code für dich nichtssagend ist, dann vermutlich deswegen, weil du Dinge wo solche Konstukte anzutreffen sind nicht programmierst. Was dich nicht unbedingt befähigt darüber zu urteilen.

    MahlErnsd schrieb:

    Natürlich kann man Endlosschleifen verwenden, wenn man etwas programmiert was ewig laufen soll, z.B. eine Armbanduhr ohne OS.

    Oder z.B. auch 1000 andere Sachen -- die nichtmal alle ewig laufen sollen. Nur halt so lange irgend eine bestimmte Bedingung erfüllt ist -- eine Bedingung die nicht von vornherein feststeht und sich an den "Schleifenenden" auch nicht prüfen lässt, wenn man sie nicht sinnlos zwischenspeichert.
    Wenn jemand natürlich bei Threads nur an Rasterlocken denkt, dann würde es mich nicht sehr wundern wenn ihm dieser Gedanke total fremd ist.

    MahlErnsd schrieb:

    Aber bei 99% aller Schleifen loop man über irgendwas, was irgendwann zu Ende ist und ich weiß nicht, wieso man diese Bedingung irgendwo mitten in der Schleife verstecken soll.

    Wenn du alle Fälle wo etwas Sinn macht wegignorierst/wegdefinierst, obwohl sie definitiv anzutreffen sind, ... dann ist die Frage wo dieses Etwas Sinn macht irgendwie ... sinnlos.



  • hustbaer schrieb:

    MahlErnsd schrieb:

    Irgendwie jetzt genau meine Antwort von oben. Und wie erwartet sogar kürzer.

    Was ich jetzt nicht wirklich als Verbesserung empfinde.
    Und... was machst du wenn die Abbruchbedingung nicht zufällig "ist Null" ist?

    Wird wohl auch als for-Schleife gehen. Aber eigentlich verwende ich weder deine noch meine Lösung. Liegt wohl einfach dran, dass mein Programmierstil nicht so C-mäßig, mit Null terminierten Strings usw., ist, sondern mit Klassen, Iteratoren und ähnlichem. Ich kann mich nicht mal an eine Stelle erinnern, wo ich überlegen musste, wie ich eine Endlosschleife vermeide, die Gelegenheit hat sich durch das verwendete Klassen/Daten-Design nie ergeben. Auch bei Multithreading gibt es ja einige andere Möglichkeiten als Warteschleifen, z.B. Futures usw.

    MahlErnsd schrieb:

    Nichts sagender Code der garkeine Abbruchbedingung enthält.

    Wenn der Code für dich nichtssagend ist, dann vermutlich deswegen, weil du Dinge wo solche Konstukte anzutreffen sind nicht programmierst. Was dich nicht unbedingt befähigt darüber zu urteilen.

    Ich weiß was das Problem sein soll, dass du zeigen willst, aber mit einer Abbruchbedingung die ... ist und einer forever Schleife um irgendwas unbekanntes, ist das als Beispiel unnütz und man kann keine oder jeder Alternative hinschreiben.



  • MahlErnsd schrieb:

    Ich kann mich nicht mal an eine Stelle erinnern, wo ich überlegen musste, wie ich eine Endlosschleife vermeide, die Gelegenheit hat sich durch das verwendete Klassen/Daten-Design nie ergeben. Auch bei Multithreading gibt es ja einige andere Möglichkeiten als Warteschleifen, z.B. Futures usw.

    Andere Leute müssen auch nicht überlegen, wie sie eine Endlosschleife vermeiden, nämlich weil sie einfach eine einsetzen, wenn das die beste Lösung ist und den verständlichsten Code produziert.

    Ist immer wieder toll wenn man Code lesen muss, der so anfängt:

    bool flag=true;
    while (flag)
    

    Und im Schleifenrumpf wird "flag" dann an zig Stellen in verschachtelten Konditionen irgendwelche Werte zugewiesen. Aber Hauptsache, man hat kein for verwendet. Und die Abbruchbedingung ist ja so auch viel klarer. Immer dann, wenn im flag im Rumpf false wird und es schafft, diesen Zustand im weiteren Verlauf beizubehalten, bricht die Schleife ab. Also eigentlich ganz einfach. Viel besser als die BWLer mit ihren breaks. Jaaa, da war wieder ein Meister am Werk.



  • Den Profis unter den Endlosschleifenvermeidern reicht das natürlich nicht. Das sieht ja fast schon wieder wie eine Endlosschleife aus. Also machen sie daraus

    bool flag=false;
    do
    {
      //...
    }
    while (flag);
    

    Das ist cool. Quasi das Gegenteil, eine Niemalsschleife mit Am-Leben-Erhalt-Ausnahme-Konditionen. Gründlicher kann man es den Endlosschleifigern ja gar nicht zeigen. Und die Abbruchbedingung wird so auch gleich noch mal klarer. Es gibt ja keine, kann man also auch nicht missverstehen. Die nennen wir jetzt nämlich anders. Der Code ist jetzt per Definition am klarsten und wartbarsten, weil kein for(;;) drin zu sehen und auch erstmal kein true auftaucht.



  • Wer echte Endlosigkeit will benutzt eh goto 😃



  • MahlErnsd schrieb:

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

    void main (void) {
        some_init_code();
        enable_interrupts();
        /* ab hier läuft dann das "eigentliche" Programm über durch
           Timer, Events, etc getriggerte ISR ab, welche main() unterbrechen */
    
        while (true) {
            lowest_prio_task1();
            lowest_prio_task2();
            /* ... */
            lowest_prio_taskN();
        }
    }
    

    Die lowest_prio_task sind dann so Sachen wie Speicherchecks oder optionale Tasks wie Messwerte abgreifen. Und wenn man das alles nicht braucht ein kurzzeitiges Einschlafen.
    Eine Abbruchbedingung/Unterbrechung braucht man nicht, da das Programm nicht terminieren soll/darf/muss. Es wird von aussen terminiert (Versorgungsspannung weg).
    Hier sollte natürlich auch klar werden warum (in diesem Anwendungsfall) der Grad der Endlosschleifenoptimierung ziemlich irrelevant ist.



  • jb2603 schrieb:

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

    Dem schließe ich mich mal an, das nehme ich aus diesem Thread mit 👍

    MfG SideWinder


Anmelden zum Antworten