Programmiertechnisches

  • Edit: Dass da was wegoptimiert wird, hat sich als falsch herausgestellt. Es war ein Fehler in den Typen. Anfängerfehler bei C/C++, wenn man hardwarenah wird.





    Angeblich optimieren viele Compiler sowas wie (i+1)<i weg. Also Überlaufprüfungen. Weil Überläufe im Sprachstandard nicht definiert sind. Würde mich freuen, zu hören, ob eure Programmiere der Quellcode mal danach durchforstet haben.


    Bei Visual Studio Community-Edition ergibt der unten stehende Quellcode die darauf folgend angegebenen Ergebnisse.


    32758 32759 32761 32762 32763 32764 32765 32766 32767 -32768 Programmende


    Also macht der das auch. (Von Hand abgetippt; kann Abschreibefehler enthalten.)

    Edited once, last by der Andreas: Hat sich ja als falsch herausgestellt. ().

  • Was willst du uns mit diesem Post sagen?


    Ich hab den schon hier im alten Forum nicht verstanden, ich meine das ist ja schön und gut aber was hat das mit RoM zu tun?

    Edit - Back to topic:


    Ja, zum Beispiel auch der GNU Compiler optimiert die komplette if-Schleife raus, sieht man (im Assembler Code den man mit g++ -S bekommt) recht einfach daran dass die Strings für "Überlauf gefunden" im Assembler Code fehlen.


    Wenn du Überläufe verhindern willst, wäre so etwas zum Beispiel hilfreicher (ich habe das include mal ausgetauscht damit das auch ohne Microsoft-Compiler geht).


    The ships hung in the sky in much the same way that bricks don’t.


    Douglas Adams in The Hitchhiker's Guide to the Galaxy

    Edited once, last by Rynak: BTT ().

  • Diogenes

    Added the Label General
  • Diogenes

    Added the Label Deutsch
  • Was willst du uns mit diesem Post sagen?

    Ich habe gesehen, dass ab und zu Regionen neu gestartet werden müssen. Ich kann mir vorstellen, dass da so ein Fehler versteckt ist. Wenn man den nicht kennt, findet man den fast nicht.


    Danke für den Tipp mit dem g++ -S!

  • Nach dem was ich so gelesen habe, und so merkwürdig es klingt, ist der Überlauf eines signed integers (egal in welcher Größe) rein vom C++ Standard her schlicht nicht definiert.


    Soll heißen, es kann sein, dass

    Code
    1. SHRT_MAX + 1 == SHRT_MIN

    gilt, es kann aber auch sein, dass

    Code
    1. SHRT_MAX + 1 != SHRT_MIN

    gilt. Und was noch viel schlimmer ist: Es kann sein, dass auf ein und dem selben Rechner, in ein und demselben Program, sowohl manchmal das eine gilt, als auch manchmal das andere gilt.


    Es mag Compiler geben, die verbindliche Festlegungen treffen, teilweise auch nur mit entsprechenden Compiler-Switches, aber das ist dann eben Compiler-abhängig. Es gibt aber auch Compiler, die nutzen die Undefiniertheit aus, denn logischerweise kann (i + 1) < i als Ergebnisse nur falsch oder undefiniert haben. Daher ist eine Optimierung, die so tut als ob es immer falsch wäre, vollkommen korrekt, genauso wie eine Optimierung, die den Überlauf nach den typischen Regeln umsetzt und mal falsch und mal wahr liefert.


    Wenn man einen definierten Überlauf haben will, sollte man unsigned anstelle von signed benutzen. Und wenn es nur um die Überlauferkennung geht, bevor sie passiert, dann kann man sie anders formulieren.


    Außerdem musst du berücksichtigen, dass es so etwas wie eine Integer Promotion gibt. Das heißt, nach Standard darf der Compiler Ausdrücke in größere Typen (meistens int) umwandeln, wenn das für ihn mehr Sinn ergibt. Das wird insbesondere vor der Verwendung in Operatoren gemacht, in dem Fall der + Operator. Und da passiert dann kein Überlauf. Genau das Problem geht das Code-Beispiel von Rynak an, indem es das Ergebnis der Addition zurück in einen short konvertiert, vor dem Vergleich.




    Der Zusammenhang zum Absturz von irgendwelchen Regionen oder Zonenevents erschließt sich mir jedoch nicht. Da fallen mir auf Anhieb ein paar Dutzend andere typische Programmierprobleme ein, die sowas verursachen könnten.

  • Mist, dass 1 vom Typ int ist, hatte ich übersehen. Ich habe jetzt mal etwas mehr gecastet und plötzlich funktioniert das Ding bei mir.

    Code
    1. if (((short)(i + 1)) < i) {
    2. std::cout << "Überlauf gefunden." << std::endl;
    3. }

    Es gibt jetzt 32758 32759 32760 32761 32762 32763 32764 32765 32766 32767 Überlauf gefunden. -32768 Programmende

    aus. Getestet mit dem GNU C++-Compiler ver. gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10) und dem aktuellen Microsoft Visual Studio Community-Edition.


    Ich bin doch ein Honk. Ich habe inzwischen gesehen dass das die ungefähr Lösung von Rynak ist. Da wird dann auch der Überlauf gefunden. Der muss im Assemblercode ein cmpw verwenden, kein cmpl. Also muss das < vom Typ short sein.


    Was die Abstürze der Regionen angeht: Ich kann mich dunkel erinnern, dass davon die Rede war, dass die Kreaturen nicht mehr angreifen. Bei einem vergleichbaren Fehler in der Aggro-Berechnung könnte das passieren. Oder habe ich da was falsch in Erinnerung?


    Aber Danke für die Mühen! Wollen wir einen allgemeinen Programmier-Thread draus machen? Mich würden eine Sprachen interessieren und ob ihr das beruflich einsetzt.


    Edit: Wer sich genauer informieren möchte, warum auch mal SHRT_MAX + 1 != SHRT_MIN sein kann, der kann sich bei der Wikipedia informieren: Die Artikel dazu sind Einerkomplement und Zweierkomplement - für "nur Vorzeichenbit" habe ich jetzt auf die Schnelle nix gefunden, kann man aber prinzipiell auch bauen.