FH München, FB 07 Informatik/Mathematik
Inhaltsverzeichnis dieser Seite:
Mit einer Wertzuweisung (engl.: "assignment") wird einer Variablen ein neuer Wert zugewiesen. Ein vorher gültiger Wert wird dabei kommentarlos und ersatzlos überschrieben. Wertzuweisung werden deshalb als "destruktiv" bezeichnet.
Eine Wertzuweisung besteht aus einer linken (das Ziel) und einer rechten Seite (die Quelle):
var = expr;
Links muß eine Variable genannt werden, rechts kann ein beliebiger Ausdruck stehen.
Aus dieser Sicht macht eine Wertzuweisung der Form
a = a + 1;Sinn, die aus mathematischer Sicht falsch ist (eine Variable kann nicht gleichzeitig zwei verschiedene Werte haben).
Dem Gleichheitszeichen kommt hier eine andere Bedeutung zu, als in der Mathematik üblich. (Ob diese Wahl geschickt war oder nicht, ist eine andere Frage.)
Ein Ausdruck, der auf der linken Seite einer Wertzuweisung stehen darf, wird "L-value" genannt (das "L" stammt von "links");
Ein Ausdruck, der auf der rechten Seite einer Wertzuweisung stehen darf, wird "R-value" genannt (das "R" stammt von "rechts");
Ein Beispiel für einen L-value ist eine Variable, wie a.
Ein Beispiel für einen R-value ist der Wert eines arithmetischen Ausdrucks, wie 2+3.
Offenkundig kann man an a zuweisen,
aber nicht an 2+3.
Ein- und dieselbe Variable spielt links und rechts des Zuweisungszeichens eine unterschiedliche Rolle:
Ein Ausdruck kann sowohl einen R-, wie auch einen L-Value, als Wert haben. Das hängt in erster Linie vom Operator, aber auch vom Kontext des Ausdrucks ab. Die arithmetischen Operatoren liefern alle R-values.
Jeder L-value ist auch als R-value verwendet werden, aber nicht umgekehrt. Das wird an der Zwitterrolle von Variablen in Abhängigkeit von Position in einer Wertzuweisung deutlich.
="
syntaktisch die Rolle eines Operators niederer Priorität
(siehe Operatorentabelle),
vergleichbar mit den arithmetischen Operatoren.
Demzufolge ist eine Wertzuweisung nichts anderes als ein Ausdruck. Der "Wert" einer Wertzuweisung ist der zugewiesene Wert (ein R-value).
Auswirkungen:
a = (b = 2);Zunächst wird die hintere Wertzuweisung ausgewertet (
b bekommt den Wert 2)
und das Ergebnis des Ausdrucks (d.h. die 2 als zugewiesener Wert)
dann in der vorderen Wertzuweisung verwendet
(a bekommt auch Wert 2).
Derartige mehrfachen Zuweisungen werden als Kettenzuweisungen bezeichnet.
Ohne die Klammern ("a = b = 2;") kommt es zum gleichen Resultat,
weil der Zuweisungsoperator von rechts nach links bindet.
Der rechte (= hintere) Operator wird zuerst ausgewertet,
anschließend der linke (= vordere):
Diese Festlegung ist sinnvoll,
weil die gegenläufige Bindungsrichtung bei einem Ausdruck wie
"a = b = 2;" einen Fehler liefern würde.
Kettenzuweisungen werden oft benutzt, um z.B. eine ganze Reihe von Variablen mit einem einheitlichen Startwert zu versorgen.
Der folgende Ausdruck
2 + (a = 3)liefert den Wert
5, weist aber "nebenbei" (siehe "Seiteneffekte")
der Variablen a den Wert 3 zu.
Von dieser Nutzung des Zuweisungsoperators ist aber i.allg. abzuraten, weil dabei schwer nachvollziehbare Fehler durch Implementierungsabhängigkeiten auftreten können (für ein übles Beispiel s.u.).
Tatsächlich kann jeder Ausdruck als Anweisung benutzt werden, allerdings hat diese Freiheit i.d.R. (d.h. für Ausdrücke ohne Seiteneffekte) nicht viel Sinn. Die Auswertung von
2;als Anweisung wird zwar ausgeführt, hat aber weiter keine Auswirkungen auf den Programmablauf (außer einem winzigen Verbrauch an Rechenzeit, sofern der Compiler die "Anweisung" nicht wegen erwiesener Sinnlosigkeit aus dem Programm streicht.).
Die Auswertung einer Zuweisung hinterläßt beobachtbare Spuren im Zustand des Programm, die Auswertung eines arithmetischen Ausdrucks dagegen nicht.
Betrachten Sie z.B. die beiden Ausdrücke
a + 2*(a + 1);und
a = 2*(a + 1);Am Ende eines Programms kann nicht festgestellt werden, ob der erste Ausdruck überhaupt nicht, 1x oder 1000x ausgewertet wurde. Dagegen läßt sich sehr wohl feststellen, daß und ggf. auch wie oft der zweite Ausdruck ausgewertet worden ist.
| Eine nachher beobachtbare Auswirkung auf den Zustand eines Programmes bezeichnet man als "Seiteneffekt". |
|---|
In gewissem Sinne ist der erste der beiden oben genannten Ausdrücke "harmlos", weil er unter keinen Umständen Schaden anrichten kann. Seine Berechnung zieht ja keinerlei feststellbare Konsequenzen nach sich, also insbesondere auch keine unbeabsichtigten.
Das gilt nicht für den zweiten Ausdruck: Seine Auswertung hinterläßt Spuren, ob gewollte oder ungewollte.
An dieser Stelle kommen die möglichen negativen Folgen von unbeabsichtigten Seiteneffekte noch nicht zum Tragen, weil die Programme klein und überschaubar sind. In größeren Softwaresystemen versucht man dagegen, mehr oder weniger ausgedehnte Programmabschnitte frei von Seiteneffekten zu halten, so daß sie als potentielle Fehlerquelle von vorne herein ausgeschlossen werden können.
Das folgende Beispiel veranschaulicht die Problematik von Seiteneffekten:
(a = 1) + (a = 2)Angenommen
a hat vorher den Wert 0.
Welchen Wert hat a nachher?
Die Antwort ist: 1 oder 2. Die Seiteneffekte der beiden Zuweisungen konkurrieren im obigen Ausdruck. Das Resultat hängt davon ab, welcher Summand zuerst ausgewertet wird. Das wiederum bleibt Privatsache des Compilers: Er kann die Reihenfolge nach Belieben wählen.
Beachten Sie, daß die Assoziativität des "+"-Operators
(links nach rechts) nur die Auswertungsreihenfolge mehrerer gleichrangiger
Operatoren regelt,
bzgl. der Anwendung eines einzelnen Operators aber keine Aussage macht.
Auf die Auswirkungen von Seiteneffekten wird weiter hinten noch eingegangen.
Die beiden Codefragmente
int a = 23;und
int a; a = 23;sind gleichwertig.
a = a + 2; // Wert von a um 2 hochzaehlen a = a / 2; // Wert von a halbieren a = a * 10; // Wert von a verzehnfachen
Dieses wiederkehrende Muster gab Anlaß für eine passende Abkürzung: Statt
var = var op exprschreibt man kürzer
var op= expr
Vorerst bleibt zwar die Schreibersparnis noch in Grenzen, die zweite Form der Wertzuweisung bringt aber eine bestimmte Absicht deutlich zum Ausdruck und trägt damit zur Lesbarkeit des Programmes bei.
Die oben gezeigten Beispiele lassen sich kürzer schreiben als:
a += 2; // Wert von a um 2 hochzaehlen a /= 2; // Wert von a halbieren a *= 10; // Wert von a verzehnfachen
Zur Auslösung von Prioritäten und Auswertungsreihenfolgen kann man sich die Kurzform jederzeit durch die entsprechende ausdrückliche Wertzuweisung ersetzt denken.
Die Warnung vor konkurrierenden Seiteneffekten gilt hier genauso wie bei normalen Wertzuweisungen.
var = var + 1geschaffen:
var++
Der Ausdruck "a++" erhöht den Wert von a um eins
und liefert den hochgezählten Wert als Ergebnis zurück.
Dieses Konstrukt wird z.B. oft in Zählschleifen benutzt.
Zum "Inkrement"-Operator gibt es den entsprechenden
"Dekrement"-Operator "--",
der den Wert der Variablen um eins herunterzählt.
Schließlich lassen sich beide Operatoren in Präfix- und in Postfix-Schreibweise verwenden, d.h. sie können der Variable voran oder nachgestellt werden.
Unabhängig von der Stellung des Operators zählt "++"
den Wert der Variablen
hoch und "--" herunter.
Die Stellung des Operators bestimmt den zurückgelieferten Wert:
Folgende Tabelle zeigt die Eigenschaften im Überblick:
| erhöhen | verringern | |
|---|---|---|
| erst Wert bestimmen, dann verändern |
x++
|
x--
|
| erst verändern, dann Wert bestimmen |
++x
|
--x
|
Letzte Änderung: Fri Sep 27 07:34:17 1996