Frage zu increment



  • Hallo,
    ich stehe scheinbar auf dem Schlauch ...
    Es geht um den Increment-Operator.
    Bei der u.s. Zuweisung ergibt die Ausgabe für X = 3, während z = 2 zugewiesen bekommt.

    Bei z ist es klar, denn der Wert (2) für y wird zugewiesen und dann inkrementiert.
    Müsste dann x nicht auch 2 zugewiesen bekommen (und danach auf 3 inkrementiert).

    Scheinbar ist die Erklärung ganz simpel, aber ich sehr grad den Wald vor Bäumen nicht.

    Danke.

    	int x = 2;
    	int y = 2;
    	int z;
    
    	x = x++;
    	z = y++;
    
    	cout << x << endl;
    	cout << z << endl;
    

  • Mod

    Und wer garantiert dir die Reihenfolge, in der die Zuweisung und das Inkrement durchgeführt werden? Vor Zeile 5 hat x den Wert 2. In Zeile 5 steht, dass sowohl x der Wert 2 zugewiesen werden soll, als auch dass x um 1 erhöht werden soll. Wenn das Semikolon erreicht ist, müssen beide Effekte passiert sein, aber in welcher Reihenfolge steht nicht fest. x könnte am Ende entweder 2 oder 3 sein, man weiß es nicht. Die Sprachdefinition geht sogar so weit, dass das Ganze vollständig undefiniert. ist Das bedeutet, es braucht nicht entweder 2 oder 3 zu sein, es könnte auch x=29 herauskommen. Oder "grüäh€". Oder es könnte pinke Hunde vodrukeln.

    In Zeile 6 ist hingegen klar, wie das Endergebnis aussieht. Da steht, dass z der Wert 2 zugewiesen werden soll, und dass y um 1 erhöht werden soll. Egal in welcher Reihenfolge man das macht, das Endergebnis für z und y ist stets das gleiche. Daher sind das Ergebnis und die Effekte dieses Ausdrucks genau definiert.



  • also eigentlich (nach meinem wissen) ist es so, dass der post-inkrement nach der zuweisung ausgeführt, bzw. der ausdruck erst ausgewertet und dann erhöht wird.

    in zeile 5 bedeutet das, dass x den wert von x (= 2) zugewiesen bekommt und danach x um 1 erhöht wird, was dann 3 macht.
    in zeile 6 bedeutet das, dass z den wert von y (= 2) zugewiesen bekommt und danach y um 1 erhöht wird, weshalb y dann auch 3 ist und z eben 2 bleibt.

    und weil das alles immer so unglaublich verwirrend ist, soll man solche spielereien bleiben lassen und sich auf eine anweisung pro zeile beschränken, weshalb ein vernünftiges programm so aussehen würde:

    int x = 2;
    int y = 2;
    int z;
    
    x = x;  //alternativ: x += 1;
    x++;
    
    z = y;
    y++;
    
    cout << x << endl;
    cout << z << endl;
    


  • @Wade1234 sagte in Frage zu increment:

    also eigentlich (nach meinem wissen) ist es so, dass der post-inkrement nach der zuweisung ausgeführt, bzw. der ausdruck erst ausgewertet und dann erhöht wird.

    Es ist undefiniertes Verhalten.
    Jeder Compiler kann da machen, was er will.
    Je nach Optimierungsstufe kann das Ergebnis anders ausfallen.

    Was würdest du bei x = x++ + x++ erwarten?

    Das Stichwort dazu wäre Sequence Point



  • @DirkB sagte in Frage zu increment:

    Was würdest du bei x = x++ + x++ erwarten?

    naja 6 bei x = 2, weil 2 + 2 + 1 + 1 nach meiner rechnung eben = 6 ist. im prinzip ist es ja eigentlich auch egal, ob da auf der cpu 2 + 2 + 1 + 1, oder 3 + 3, oder 3 + 2 + 1 oder 2 + 1 + 2 + 1 oder was auch immer gerechnet wird.

    mein buch sagt jedenfalls genau das aus: https://www.bilder-upload.eu/bild-d48b0d-1572510061.jpg.html

    aber ich habs eben mal durch den clang geschickt und dieser meckert rum und gibt 5 aus. 🙄 ein grund mehr, solche spielereien einfach bleiben zu lassen und eine anweisung pro zeile zu verwenden.🤨


  • Mod

    @Wade1234 sagte in Frage zu increment:

    @DirkB sagte in Frage zu increment:

    Was würdest du bei x = x++ + x++ erwarten?

    naja 6 bei x = 2, weil 2 + 2 + 1 + 1 nach meiner rechnung eben = 6 ist. im prinzip ist es ja eigentlich auch egal, ob da auf der cpu 2 + 2 + 1 + 1, oder 3 + 3, oder 3 + 2 + 1 oder 2 + 1 + 2 + 1 oder was auch immer gerechnet wird.

    mein buch sagt jedenfalls genau das aus: https://www.bilder-upload.eu/bild-d48b0d-1572510061.jpg.html

    aber ich habs eben mal durch den clang geschickt und dieser meckert rum und gibt 5 aus. 🙄 ein grund mehr, solche spielereien einfach bleiben zu lassen und eine anweisung pro zeile zu verwenden.🤨

    Ich glaube, du hast das Problem nicht wirklich verstanden...



  • @SeppJ naja doch: die erwartungshaltung wäre, dass das so funktioniert, wie von mir beschrieben, weil postfix "führe nach der auswertung aus" bedeutet / bedeuten soll und zuweisung "werte den ausdruck auf der rechten seite aus und schreibe den wert auf die linke seite" bedeutet / bedeuten soll.

    die realität sieht so aus, dass der compiler das so machen kann, aber nicht so machen muss und der clang in meinem speziellen fall das auch nicht so machen wird, weil der standard das laut eurer aussage nicht so einfordert, was ich eigentlich ein bisschen komisch finde.


  • Mod

    @Wade1234 sagte in Frage zu increment:

    @SeppJ naja doch: die erwartungshaltung wäre, dass das so funktioniert, wie von mir beschrieben, weil postfix "führe nach der auswertung aus" bedeutet / bedeuten soll und zuweisung "werte den ausdruck auf der rechten seite aus und schreibe den wert auf die linke seite" bedeutet / bedeuten soll.

    Nein, eben nicht. Wie kommst du darauf? Du verweist auf dein Buch, aber ich kann deinem Buch keinen Vorwurf machen, da steht nichts dergleichen drin.

    @Wade1234 sagte in Frage zu increment:

    die realität sieht so aus, dass der compiler das so machen kann, aber nicht so machen muss und der clang in meinem speziellen fall das auch nicht so machen wird, weil der standard das laut eurer aussage nicht so einfordert, was ich eigentlich ein bisschen komisch finde.

    Auch nicht. Das ist nicht "da kommt irgendwas compilerabhängiges raus", dass ist undefiniert. Das ist das schlimmste, was du haben kannst. Da kannst du keine Erwartungen anlegen, was "in der Realität" rauskommt. In der "Realität" sind da schon krasse Dinge passiert, weil Leute so gedacht haben wie du.



  • @SeppJ also ich interpretiere es jedenfalls so.


  • Mod

    @Wade1234 sagte in Frage zu increment:

    @SeppJ also ich interpretiere es jedenfalls so.

    Und deswegen ist es wichtig, dass du genauer liest und genau mitdenkst. Denn das steht da nicht. Du machst einen nicht gerechtfertigten Gedankensprung von "nach der Auswertung des Postfix" zu "nach dem nächsten Sequenzpunkt".

    Da der Computer immer ganz genau tut, was du ihm sagst, und nicht das, was du meinst, ist es wichtig, dass du die Regeln ganz genau liest und verstehst, und da keine eigene Interpretation rein bringst.



  • @Wade1234 sagte in Frage zu increment:

    also ich interpretiere es jedenfalls so

    Das Problem hier ist die Zuweisung an x innerhalb des Sequence Points (der endet hier beim ; )

    clang mag hier auf der rechten Seite 2+3 auswerten (da wäre x dann 4. Dann folgt die Berechnung und Zuweisung an x. Also 5

    Ist aber auch egal, da es undefiniert ist.



  • @Wade1234
    Postfix garantiert dass der Wert der inkrementierten/dekrementierten Variable (nicht! des gesamten Ausdrucks) vor dem Ändern der Variable ermittelt wird, und das Ändern der Variable dann danach passiert. Eine Garantie dass das Ändern der Variable noch weiter verzögert wird, z.B. bis nach dem Assignment in diesem Beispiel, gibt es nicht.

    D.h. es könnte 2 als Wert ermittelt werden, dann x inkrementiert, und dann erst das Assignment x = 2 durchgeführt.

    Welche weiteren Regeln es diesbezüglich noch gibt hat sich soweit ich weiss auch zumindest einmal mit C++11~17 geändert. Das sind Regeln die ich nicht auswendig kenne. Ich schreibe solchen Code nicht. Macht doch überhaupt keinen Sinn wenn man beim Code Lesen dauernd über Konstrukte stolpert wo man so esoterische Regeln kennen muss um zu verstehen ob sie überhaupt definiertes Verhalten haben. Und es ist viel zu leicht damit Mist zu bauen.



  • @DirkB Gibt es Sequence-Points in C++11 noch? Ich dachte das wurde durch anders formulierte Regeln ersetzt.


  • Mod

    @hustbaer sagte in Frage zu increment:

    @DirkB Gibt es Sequence-Points in C++11 noch? Ich dachte das wurde durch anders formulierte Regeln ersetzt.

    Es ist jetzt anders formuliert, ja, aber es kommt aufs gleiche raus. Jetzt gibt es Aussagen darüber, welche Art von Effekten "vor" oder "nach" anderen Effekten auftreten. Da hier aber alle Effekte von der gleichen Art sind und auf dem selben Objekt arbeiten, ist das Verhalten nach wie vor undefiniert.

    PS: In C++17 hat man es aber noch feiner unterteilt, da fallen manche dieser Beispiele weg. i = i++; ist jetzt wohldefiniert. i = i++ + ++i; aber nach wie vor nicht.

    PPS: Der Preis dafür ist, das aus 5 Regeln nun 21 geworden sind 🙀



  • @SeppJ Danke 🙂
    BTW: Was heisst "vodrukeln"?


  • Mod

    @hustbaer sagte in Frage zu increment:

    @SeppJ Danke 🙂
    BTW: Was heisst "vodrukeln"?

    Das ist so etwas wie verdräkeln, aber weniger kubunt.



  • @SeppJ Ah, verdammt. Wenn mir der Name dieser überaus geheimen Geheimsprache einfallen würde könnte ich jetzt die Regeln nachlesen.



  • @SeppJ sagte in Frage zu increment:

    PPS: Der Preis dafür ist, das aus 5 Regeln nun 21 geworden sind 🙀

    Naja dafür sind die aber halbwegs einfach.


  • Mod

    @hustbaer sagte in Frage zu increment:

    @SeppJ sagte in Frage zu increment:

    PPS: Der Preis dafür ist, das aus 5 Regeln nun 21 geworden sind 🙀

    Naja dafür sind die aber halbwegs einfach.

    Naja. Ist so meiner Meinung nach eher so wie wenn man aus

    if isalpha(c)
       prio = 1;
    else if isdigit(c)
       prio = 2;
    

    stattdessen

    if c == 'a'
       prio = 1;
    else if c == 'b'
       prio = 2;
    // ...
    else if c == 'z'
       prio = 26;
    else if c == '0'
       prio = 27;
    // ...
    

    macht.



  • @SeppJ Ja verstehe schon was du meinst. Andrerseits... wer Code schreibt wo das ne Rolle spielt, der ist mMn. selbst schuld. Klar, dazu muss man wissen was evtl. problematisch werden könnte. Aber man muss nicht die ganzen Regeln kennen wo es dann doch definiert ist.


Anmelden zum Antworten