Laden...

++ Operator verhält sich unerwartet

Erstellt von Grundkurs vor 11 Jahren Letzter Beitrag vor 11 Jahren 1.911 Views
G
Grundkurs Themenstarter:in
13 Beiträge seit 2005
vor 11 Jahren
++ Operator verhält sich unerwartet

Hallo!
In einem C#-Test sollte ich heute den Output von folgendem Stück Code herausfinden:

   
 static void Main(string[] args)
        {
            var i = 5;
            for (int j = 0; j < 5; j++)
            {
                i = i++;
            }
            Console.Write(i);
            Console.ReadKey(); 
        }

Die Antwort, denkbar einfach, sollte eigentlich 10 sein. Doch zu meiner großen Überraschung spuckt der Compiler eine 5 aus.
Der gleiche Code in C++


#include <iostream>

int main()
{
	int i = 5;
	for(int j = 0; j < 5; j++)
	{
		i = i++;
	}
	std::cout << i; 
	std::cin.get(); 

}

spuckt hingegen eine 10 aus. Ich verstehe schon allein nicht, warum C# 5 statt 10 ausgibt, denn die Variable i sollte doch in jedem Schleifendurchlauf um 1 erhöht werden...? Weiß jemand wieso sich der ++ Operator in C# so benimmt?

1.002 Beiträge seit 2007
vor 11 Jahren

Hallo Grundkurs,

der Ausdruck

i++;

ist die Kurzform der folgenden Anweisung:

i = i + 1;

Sie erhöht den Wert der Variable i um 1. Der Rückgabewert der Kurzform dieses Ausdrucks ist jedoch nicht der Wert der erhöhten Variable, sondern der der noch nicht erhöhten. Dieser Wert (5 in deinem Beispiel) wird zurückgegeben; die Variable i wird erst anschließend inkrementiert. Der Wert der Variable bleibt in deinem Beispiel deshalb konstant 5, da du ihr den noch nicht erhöhten Wert zuweist und somit Durchlauf für Durchlauf effektiv nichts machst.

Um dein Beispiel zum Laufen zu bringen, lass einfach die Zuweisung weg und schreibe lediglich folgende Zeile:

i++;
i = ++i;

Dabei wird der Wert von i erst erhöht und anschließend (redundant, da doppelt) zugewiesen. Das dient jedoch nur zu Illustrationszwecken und ist nicht zu empfehlen.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

925 Beiträge seit 2004
vor 11 Jahren

Hat jemand eine Erklärung dafür, weshalb C++ das anders macht als C#?

1.002 Beiträge seit 2007
vor 11 Jahren

Hallo 7.e.Q,

je nach Anwendungsfall kann es durchaus sinnvoll sein, über beide Varianten der Inkrementierung zu verfügen, wie der folgende Pseudocode zeigt:

int i = 0;
object[] demoArray = new object[...];

foreach (...)
{
    demoArray[i++] = ...
}

Würde der erhöhte Wert der Variablen zurückgegeben werden, würde die erste Zuweisung bereits den Index 1 verwenden und nicht, wie gewünscht, den Index 0.

Das Ganze nennt sich übrigens Prä- bzw. Post-Inkrementierung. Analog dazu gibt es ebenfalls die Prä- bzw. Post-Dekrementierung mit dem Operator --.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

G
Grundkurs Themenstarter:in
13 Beiträge seit 2005
vor 11 Jahren

Hallo m0rius!
Danke erstmal für die ausführliche Antwort und die Erklärung, warum im C# Code i nicht erhöht wird. Die Frage von 7.e.Q bezieht sich darauf, wieso der gleiche Code, bei dem in C# die Variable immer "auf der Stelle tritt", in C++ hingegen doch erhöht wird. Das ist halt auch seltsam. Ich meine der Code ist wirklich identisch (die kleinen Syntax-Anpassungen ausgenommen).

1.002 Beiträge seit 2007
vor 11 Jahren

Hallo Grundkurs,

ohne mich jetzt genauer mit der Dokumentation von C++ beschäftigt zu haben, vermute ich, dass die Post-Inkrementierung in C++ so implementiert ist wie die Prä-Inkrementierung in C#. Dies wurde, schätze ich, aus o.g. Gründen in C# abgeändert.

m0rius

Hinweis von herbivore vor 11 Jahren

Nein, Grundsätzlich gibt es auch in C++ die Unterscheidung zwischen Pre- und Post-Increment.

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

G
Grundkurs Themenstarter:in
13 Beiträge seit 2005
vor 11 Jahren

Ich habe endlich rausgefunden warum c++ den Wert 10 ausgibt und c# den Wert 5:

Side effect operators (++, --, =, +=, -=, *=, /=, %=, &=, |=, ^=, <≤, and >≥) may cause unexpected results if they are used on the same variable or memory location more than once in the same expression. The order in which side effects occur within an expression is not specified.

Das steht hier: KB50694: INFO: Evaluation Order of Expression and Function Args Undefined
Wenn ich das also richtig verstehe: Inkrement-oder Dekrement-Operatoren können, soweit die Variable mehr als einmal in der gleichen Anweisung benutzt wird, zu nicht spezifiziertem Verhalten führen.
Auf der Seite wird z.B. der Befehl

 a[i] = i++;  /* UNDEFINED */ 

als Beispiel für undefiniertes Verhalten angeführt, der meinem von oben fast gleicht.

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo Grundkurs,

klar ist, der Wert von i (im Speicher) wird abgerufen (z.B. in ein Prozessorregister) und wieder an i (im Speicher; aus dem Prozessorregister) zugewiesen. Und es ist klar, dass der Wert von i (im Speicher) nach dem Abrufen erhöht wird. Die entscheidenden Frage ist, wird er sofort nach dem Abrufen erhöht (so wie bei C#) oder erst ganz am Ende, nachdem alle anderen Operationen (also auch die Zuweisung) durchgeführt wurde (so wie in C++). Undefiniert ist also nur, zu welchem Zeitpunkt nach dem Abrufen der Wert von i erhöht wird. Sicher ist, dass er erst nach dem Abrufen erhöht wird. Meine Erwartung (sowohl in C# als auch in C++) wäre gewesen, dass der Wert sofort nach dem Abrufen erhöht wird. Der Thread hat mir gezeigt, dass man in C++ davon doch nicht ausgehen kann.

C#:
Wert von i abrufen (5)
i erhöhen (6)
Abgerufenen Wert (5) an i zuweisen (5)

C++:
Wert von i abrufen (5)
Abgerufenen Wert (5) an i zuweisen (5)
i erhöhen (6)

herbivore

925 Beiträge seit 2004
vor 11 Jahren

Ah, alles klar, unterschiedliches (bzw. bei C# überhaupt erst vorhandenes) Speichermanagement ist also der Grund für das unterschiedliche Verhalten zwischen C++ und C#. Wieder was gelernt.

W
123 Beiträge seit 2008
vor 11 Jahren

Hallo,

Der Ausdruck:

i = i++;

ist auch bei C/C++ undefiniert. Es gibt hier keinen Sequenzpunkt, aber der Wert der Variablen wird zweimal verändert. Der Standard erlaubt aber nur eine Änderung zwischen zwei Sequenzpunkten. Es ist also purer Zufall, dass bei Grundkurs "10" herausgekommen ist. Es ist ebenfalls denkbar, dass "5", wie beim C#-Beispiel, herauskommt.

Sequenzpunkte

Gruß
wolpertinger