Schleifen - Wieso keine Sicherheit?



  • (gast) schrieb:

    @SeppJ: Okay, überredet 😉 Irgendwie muss man ja auch absichtliche "Endlos"-Schleifen programmieren können
    Sachen wie

    while(1!=2){
        ...
        if(condition){break;}
    }
    

    sind ja weit verbreitet.

    Äh, while (true) oder einfach for (;;) ?


  • Mod

    Michael E. schrieb:

    SeppJ schrieb:

    Dieses hier ist bloß eine ungewöhnliche Programmierstruktur mit genau definiertem Verhalten, welches auch keinen Fehler hervorruft.

    Eigentlich handelt es sich hier um Undefined Behaviour. Das müsste in http://blog.regehr.org/archives/161 stehen. Schlag mich, wenns nicht so ist.

    Woah! Das ist aber mal eine obskure Klausel! Ich erinnere mich zwar da dran, diese mal gelesen zu haben, aber an diese Konsequenzen hätte ich nie gedacht. Das hat ja richtig weitreichende Folgen für die Standardkonformität harmloser Programme!
    Dann lass uns vielleicht lieber annehmen, dass das Programm gutes altes C89 ist mit definiertem Überlaufverhalten und ohne Klauseln über das Verhalten von Schleifen. 🙂



  • Noch ne kleine Anmerkung: In C++11 ist dieses Verhalten explizit nicht mehr auf Schleifen begrenzt, sondern gilt beispielsweise auch bei endlosen rekursiven Aufrufen. Hab die entsprechende Stelle aber gerade nicht zur Hand.

    Edit: §1.10.24:

    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]



  • @Michael E.
    Ja, die ganze Geschichte mit "Programm/Funktion das nicht terminiert => UB => Compiler dürfen ganz wild Dinge wegoptimieren" hat ja durchaus für einige Diskussionen gesorgt.
    Das Argument des "pro" Lagers war dabei immer dass das bestimmte Optimierungen erlaubt die sonst nicht möglich wären.

    Was mich aber interessieren würde: gibt es da ein gutes Beispiel für eine Optimierung, die ohne diese Regel nicht möglich wäre, und wo auch etwas sinnvolles dabei rauskommt?

    Ich kann mir nämlich vorstellen dass bestimmte Optimierungen dadurch vielleicht einfacher werden, aber mir fällt nix ein wo es ohne diese Regel wirklich nicht möglich wäre.


  • Mod

    Die leere Endlosschleife wird schneller ausgeführt 🙂 .

    Um etwas sinnvoller zu werden: Gegeben ein Programmteil

    unsigned N;
    cin >> N;
    unsigned counter = 0;
    for (unsigned short i = 0; i < N; ++i)
     ++counter;
    // N im Folgenden nicht mehr benutzt.
    

    Könnte komplett durch

    unsigned counter;
    cin >> counter;
    

    ersetzt werden, wenn man weiß, dass die Schleife terminiert.

    Solche Fälle sollten sich leicht mehr (und sinnvoller) konstruieren lassen, wenn das Ergebnis einer Schleife für den Compiler berechenbar von den Kontrollvariablen abhängt (gar nicht so selten!), aber in einigen Ausnahmefällen die Schleife gar nicht abbrechen würde.



  • Wenn die Eingabe fehlschlägt, enthält die Variable einen undefinierten Wert.



  • 314159265358979 schrieb:

    Wenn die Eingabe fehlschlägt, enthält die Variable einen undefinierten Wert.

    War vorher auch so.



  • 314159265358979 schrieb:

    Wenn die Eingabe fehlschlägt, enthält die Variable einen undefinierten Wert.

    Für mich kam bisher ein Blockierskript für einzelne User nicht infrage. Wenn du jetzt allerdings jeden Beitrag von SeppJ kommentieren willst, weil du Unrecht hattest und das nicht einsehen willst, wanke ich sehr in meiner Haltung.



  • Ich hatte nicht Unrecht.



  • hustbaer schrieb:

    Ich kann mir nämlich vorstellen dass bestimmte Optimierungen dadurch vielleicht einfacher werden, aber mir fällt nix ein wo es ohne diese Regel wirklich nicht möglich wäre.

    Es ist einfacher, ein Programm auf Seiteneffekte zu testen, als auf Terminierung. Wenn der Compiler ersteres aber beweisen kann, darf er den entsprechenden Code eventuell trotzdem nicht wegoptimieren, wenn er Terminierung nicht zeigen kann.


  • Administrator

    hustbaer schrieb:

    Was mich aber interessieren würde: gibt es da ein gutes Beispiel für eine Optimierung, die ohne diese Regel nicht möglich wäre, und wo auch etwas sinnvolles dabei rauskommt?

    Ich hätte da eher eine andere Frage: Gibt es überhaupt sinnvolle Schleifen, welche in diese Kategorie fallen? Das Ganze scheint mir ein etwas theoretisches Konstrukt zu sein.

    Ich zweifle daher an diesen "weitreichenden Folgen", wie es SeppJ gesagt hat.

    Grüssli



  • (gast) schrieb:

    eine Warnung ausspucken sollte (hat mein g++ 4.6.1 selbst mit -Wall -pedantic nicht gemacht 😞 ). Dass die Abbruchbedingung hier nicht erreicht werden kann ist offensichtlich - trotzdem kein Grund overflows komplett zu verbieten. Das hier funktioniert nämlich:

    for(short i=32000; i<-32000 || i>0; ++i){}
    

    -Wextra ist gefragt.

    ethon@fleck:~$ gcc -Wall -Wextra test.cpp
    test.cpp: In Funktion »int main()«:
    test.cpp:10:22: Warnung: Vergleich ist durch beschränkten Wertebereich des Datentyps stets »wahr« [-Wtype-limits]



  • cvcv schrieb:

    for ( short int i = 0; i <= 32767; i++) 
         std::cout << i << "\n";
    

    Wieso setzt C++ am Ende des Schleifenkörpers nicht einfach ein conditional jump, der bei overflow-flag ausgeführt wird? Es wurde in C++ doch einige Sachen extra "sicherer" gemacht, zB strings nicht mehr anfällig für overflows's ... wieso wurde diese kleine Sache nicht implementiert?

    Weil der Überlauf bei Schleifenzählern wohl eines der Probleme ist, das am seltensten auftritt. Bei Berechnungen tritt manchmal ein Überlauf auf. Und bei Strings würde das garnichts bringen, ein Pufferüberlauf hat nichts mit einem Ganzzahlüberlauf zu tun und läßt sich nicht so abfangen.


Anmelden zum Antworten