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



  • 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