Kleines Verständnis Problem



  • Hallo,
    ich verstehe grade nicht ganz wie in der Konsole die Ergebnisse zustande kommen, der Code kommt aus einer Altklausur. Ich habe noch Kommentare noch hinzugefügt.

    1.Code

    for(int i=1; i<10; i=i<<1){
            char a=i+64;            
            cout <<a;
        }
    
    // i=1 -> a=65->A
    

    Wie kann man hier den Interationsschritt verstehen i=i<<1, bzw. wie kommt man hier auf das Ergebnis ABDH?

    2.Code

    int d=3,e=4;
        d+= e++ % 2;        // e++ -> e=5; e%2=1; d=d+1->d=4
        d= --d*e;           // (d-1)*e=3*5=15
        cout <<endl<<d;
    

    Wieso ist d=10 welche Reihenfolge wird hier zuerst berechnet?

    VG



  • @Florian200 sagte in Kleines Verständnis Problem:

    1.Code

    for(int i=1; i<10; i=i<<1){
            char a=i+64;            
            cout <<a;
        }
    
    // i=1 -> a=65->A
    

    Wie kann man hier den Interationsschritt verstehen i=i<<1, bzw. wie kommt man hier auf das Ergebnis ABDH?

    Mit dem Ausdruck i << 1 werden alle Bits in i um eine Stelle nach links verschoben, und das am weitesten rechts stehende Bit auf 0 gesetzt. Effektiv ist das eine Multiplikation mit 2, der Basis im Binärsystem. Analog dazu wäre in unserem bekannten 10er-System alle Ziffern um eine Stelle nach links zu verschieben und rechts eine 0 aufzufüllen. Das ist dann äquivalent zu einer Multiplikation mit 10, der Basis des Dezimalsystems.

    i nimmt in der Schleife also die Werte 1, 2, 4 und 8 an. Durch Addition von 64 erhält man folglich die ASCII-Werte für A, B, D und H, die du entsprechend in der Ausgabe siehst.

    2.Code

    int d=3,e=4;
        d+= e++ % 2;        // e++ -> e=5; e%2=1; d=d+1->d=4
        d= --d*e;           // (d-1)*e=3*5=15
        cout <<endl<<d;
    

    Wieso ist d=10 welche Reihenfolge wird hier zuerst berechnet?

    Bei e++ handelt es sich um ein Post-Inkrement. Der Ausdruck wird zuerst ausgewertet und erst anschliessend wird 1 hinzuaddiert. Daher ist e++ % 2 = 4 % 2 = 0 und erst nach dieser Zeile erhält e den Wert 5. Somit ist dann (d - 1) * e = 2 * 5 = 10. Anders verhielte es sich bei einem Prä-Inkrement ++e, da würde dann tatsächlich 15 herauskommen. Wenn du den Code in ausführbarer Form vorliegen hast, kannst du das ja mal ausprobieren.


  • Mod

    1. << ist der Linksschiebeoperator, der verschiebt einen Wert im Binärsystem um die angegebene Stellenzahl nach links und füllt den Rest mit Nullen auf. Beispielsweise würde aus binär 1001 (=9), wenn man es um 3 nach links verschiebt 1001000 (=36). Und das wird hier halt mit Startwert 1 und einer Verschiebung um 1 gemacht, man bekommt also (binär) 1 (=1), 10 (=2), 100 (=4), 1000 (=8), 10000 (=16). Dabei wird dann bei der 16 abgebrochen, da 16 nicht mehr kleiner als 10 ist. Es gäbe noch viel mehr über den Operator zu erzählen, aber das kannst du selber nachlesen.
    2. d= --d*e; ist undefiniert, und da kann alles mögliche rauskommen. Und zwar wirklich alles. Selbst Freitag, gelb, oder Zöglfrex.


  • @SeppJ sagte in Kleines Verständnis Problem:

    1. d= --d*e; ist undefiniert, und da kann alles mögliche rauskommen. Und zwar wirklich alles. Selbst Freitag, gelb, oder Zöglfrex.

    Oh ja, in der Tat (schäm! 😓)! Auch wenn meine Erklärung durchaus korrekt beschreibt, was dieser spezielle Compiler an der Stelle anstatt Zöglfrex macht (also wie die 10 zustande kommt), so ist das gemäss Standard tatsächlich UB 😉


  • Mod

    Sofern man das Pech hat, dass nichts absurdes wie Zöglfrex herauskommt (wodurch man den Fehler hoffentlich bemerken würde), so ist aber immerhin auch 9 ein ebenso vertretbares Ergebnis wie 10. Schließlich kann man die Zeile ebensogut auch als "d = (3-1) * 5, dann Dekrement" verstehen.



  • Okay super, danke habs verstanden 😉



  • @SeppJ sagte in Kleines Verständnis Problem:

    Sofern man das Pech hat, dass nichts absurdes wie Zöglfrex herauskommt (wodurch man den Fehler hoffentlich bemerken würde), so ist aber immerhin auch 9 ein ebenso vertretbares Ergebnis wie 10. Schließlich kann man die Zeile ebensogut auch als "d = (3-1) * 5, dann Dekrement" verstehen.

    Ich glaube aber auch eher, dass das primäre Verständnisproblem von @Florian200 beim Postinkrement lag und die Frage auch aufgekommen wäre, wenn es in Zeile 3 kein UB gäbe. Insofern ganz gut, das nochmal etwas aufgedröselt zu haben. Dennoch richtig auf das UB hinzuweisen und bei einer Klausur mit fähigen Dozenten sollte "weil UB" ebenfalls eine korrekte Antwort sein 😉



  • Oder vielleicht doch noch was. Wie ist d=--d*e; undefiniert. Die Zahlenwerte sind doch gegeben ?


  • Mod

    @Florian200 sagte in Kleines Verständnis Problem:

    Oder vielleicht doch noch was. Wie ist d=--d*e; undefiniert. Die Zahlenwerte sind doch gegeben ?

    Da sind zwei gleichzeitige Änderungen an d, nämlich einerseits "d gleich das was rechts vom = steht" und andererseits "verringere den Wert von d um 1". Die Reihenfolge davon ist nicht definiert, und das Ergebnis ist daher undefiniert. Es ist zwar klar, dass rechrs vom = der Wert 10 steht, aber nicht ob das Dekrement vor oder nach der Zuweisung passiert (also ob d hinterher 10 oder 9 ist). Und bei C++ gilt, dass solche undefinierten Dinge dazu führen, dass da kompletter Unfug rauskommen darf, nicht bloß eine der beiden Möglichkeiten, die hier zur Auswahl stehen. Daher darf eben auch Zöglfrex rauskommen. Oder meinetwegen die Festplatte formatiert werden, die Spülmaschine frisst den Hund, oder sonstwas. Praktisch wird es natürlich meistens 9 oder 10 sein, aber das hilft dir ja erstens nix, wenn du es nicht weißt, und zweitens wird dir dann wenn es wirklich drauf ankommt, dass kein kompletter Unsinn herauskommt, doch kompletter Unsinn herauskommen.

    Was dir vielleicht nicht so klar ist: --d ist nicht das gleiche wie d-1. Es mag zwar den gleichen numerischen Wert haben wie d-1 aber es bedeutet eben auch zusätzlich den Nebeneffekt, die Variable d um den Wert 1 zu verringern. Da kann und müsste man jetzt eigentlich noch viel mehr zu schreiben, aber du kannst dir auch die einfache Regel merken, dass du nicht mehrere Änderungen an der gleichen Variable machst zwischen zwei Semikolons. Und halt beachtest, dass die ++ und -- Operatoren eben auch eine Änderung sind.
    Wenn du mehr lesen möchtest, findest du hier einen Aufsatz: https://stackoverflow.com/a/4176333/11208562



  • Hallo SeppJ,

    das dachte ich bisher auch, aber seit C++17 ist das eindeutig definiert: C++ Standard: 7.6.19 Assignment and compound assignment operators
    Hier noch der Reddit-Post, wo ich genauso wie du geantwortet hatte: I thought I understood postfix increment operator


  • Mod

    Ja, das steht ja auch in dem von mir verlinkten Aufsatz. Muss aber zugeben, dass mir das bisher nicht bewusst war -- ich schreibe ja schließlich nicht solche Ausdrücke und werde es auch in Zukunft nicht tun.



  • @SeppJ sagte in Kleines Verständnis Problem:

    die Spülmaschine frisst den Hund

    🤣


Log in to reply