C++-Programmierung: Ausdrücke und Operatoren

Alte Seite
Diese Seite gehört zum alten Teil des Buches und wird nicht mehr gewartet. Die Inhalte sollen in das neue Buch einfließen: C++-Programmierung/ Inhaltsverzeichnis.
Eine aktuelle Seite zum gleichen Thema ist unter C++-Programmierung/ Einführung in C++/ Rechnen (lassen) verfügbar.

Operatoren verbinden Variablen, Konstanten und Literale zu Ausdrücken.

Operatoren Bearbeiten

Arithmetische Operatoren Bearbeiten

Die Operatoren + (Addition), - (Subtraktion), * (Multiplikation) und / (Division) haben die aus der Mathematik geläufige Bedeutung. Es gilt die Regel „Punkt vor Strich“. Mittels Klammern () können Ausdrücke gruppiert und so die Reihenfolge der Berechnung beeinflusst werden. Beispiel:

int main(void)
{
  int a = 3, b;
  b = a*3+1;    //nach der Operation b=10
  b = a*(3+1);  //nach der Operation b=12
  return 0;
}

Die arithmetischen Operatoren können auf alle Basistypen angewendet werden. Haben beide Operanden denselben Typ, so ist dies auch der Typ des Resultats. Ansonsten werden die üblichen Umwandlungen (usual arithmetic conversions) vorgenommen, z.B. wenn ein int und ein float addiert werden, ergibt sich ein float.

Das ist in den meisten Fällen nicht sehr codenend, außer bei der Division. Dividiert man zwei Ganzzahlen, so ergibt sich nach obiger Regel wieder eine Ganzzahl, mögliche Nachkommastellen werden also abgeschnitten. Die Anweisung

float a = 3/4;

weist deshalb der Variablen nicht etwa den Wert 0.75, sondern 0 zu!

Der Rest bei ganzzahliger Division kann mit dem Operator % (Modulo) errechnet werden:

int a=9, b=2;
int x = a/b; // ergibt x=4
int y = a%b; // ergibt y=1

Zuweisungsoperatoren Bearbeiten

Weil Zuweisungen der Art a = a+2; sehr häufig vorkommen, hat C++ neben dem Gleichheitszeichen noch weitere Zuweisungsoperatoren.

Dies sind (unter anderem) +=, -=, *=, /=, %=:

int a = 9;
a += 5;    //dasselbe wie a=a+5;
a -= 5;    //dasselbe wie a=a-5;
a *= 5;    //dasselbe wie a=a*5;
a /= 5;    //dasselbe wie a=a/5;
a %= 5;    //dasselbe wie a=a%5;

Wenn auf der rechten Seite ein Ausdruck steht, wird dieser berechnet und dann für die Zuweisung verwendet:

int a = 9;
a *= 3+a;   // jetzt ist a == 108
a *= 3*a+a; // jetzt ist a == 46656

Inkrement und Dekrement Bearbeiten

Mit den Operatoren ++ und -- wird ein Wert um 1 erhöht bzw. vermindert. Wobei man unterscheiden muss, ob der Operator einer Variablen vor- oder nachgestellt wird. Steht der Operator vor der Variablen (prefix increment), so wird zuerst inkrementiert und dann der Wert zurück gegeben. Steht er nach der Variablen (postfix increment), ist es umgekehrt. Wird der Wert überhaupt nicht zurückgegeben, ist der Rückgabewert des Ausdrucks natürlich belanglos. In diesem Fall ist es egal, ob man ++a; oder a++; schreibt.

#include <iostream>

using namespace std;

int main(void)
{
  int a = 9;
  a++;          //a=10, ++a wäre hier dasselbe
  a--;          //a=9
  cout << a--;  //a=8 Ausgabe=9
  cout << --a;  //a=7 Ausgabe=7
  return 0;
}

String-Operatoren Bearbeiten

Die Klasse std::string der C++-Standardbibliothek besitzt mehrere Operatoren, die die Arbeit mit Zeichenketten (strings) vereinfachen: die String-Verkettung ((con)catenation) + und die Zuweisungsoperatoren = und +=. Außerdem gibt es den Operator [], um auf die einzelnen Elemente des Strings zuzugreifen.

#include <string>

using namespace std;

int main(void)
{
  string s1;
  s1 = "Space";
 
  string s2("Shuttle");

  s1 += s2;                    // s1 = "SpaceShuttle"
  s2 = s1 + "-" + s2;          // s2 = "SpaceShuttle-Shuttle"
  char c = s1[0];              // c = 'S', Index beginnt bei 0

  s2 = "Space-" + "Shuttle";   // ungültiger Ausdruck, da weder "Space-" noch 
                               // "Shuttle" vom Type std::string sind

  return 0;
}

Weitere Operatoren Bearbeiten

Im Kapitel Kontrollstrukturen haben Sie bereits die Vergleichs- und Logikoperatoren kennen gelernt. Für die arithmetischen Basistypen gibt es weitere Operatoren, z.B. die Bit-Operatoren, die C++ sämtlich von C übernommen hat. Wir verweisen auf die Liste im Anhang.

Ausdrücke Bearbeiten

Ein Ausdruck ist eine Folge von Operanden und Operatoren. Die Syntaxregeln der Programmiersprache legen fest, wie Ausdrücke gebildet werden können. Dass diese Regeln eingehalten werden, z.B. die öffnenden und schließenden Klammern zueinander passen und die Operanden jeweils den richtigen Typ haben, kontrolliert der Compiler. Um die über die reine Syntaxprüfung hinausgehende „tiefere Bedeutung“ eines Ausdrucks müssen Sie sich selbst kümmern.

Hierarchische Struktur Bearbeiten

Der C++-Sprachstandard legt in einer Reihe grammatischer Regeln fest, wie komplizierte Ausdrücke stufenweise aus einfacheren aufgebaut werden. Auf der untersten Hierarchieebene finden Sie die Primärausdrücke. Dazu zählen Literale - z.B. 123 (eine Ganzzahl), -4.56778 (eine Fließkommazahl), 'A' (ein Textzeichen), "Ich bin ein String" (eine Zeichenkette, hat den Typ array of char und kann einer Instanz der Klasse std::string direkt zugewiesen werden) - und Namen, die Variablen, Konstanten und Referenzen bezeichnen.

Dort wo ein Name erlaubt ist, darf immer auch ein Ausdruck des passenden Typs stehen, der abhängig von den Prioritätsregeln (siehe unten) ggf. in Klammern () gesetzt werden muss. Einzige Einschränkung ist, dass manche Operatoren so genannte L-Werte als Operanden verlangen.

L-Werte Bearbeiten

Ist a eine Variable vom Typ int, so stellt

a = 12;

eine legale Zuweisung dar,

12 = a;

hingegen nicht. L-Werte heißen diejenigen Ausdrücke, die auf Speicherbereiche verweisen und deshalb auf der linken Seite einer Zuweisung stehen dürfen, das sind: Variablen, Referenzen und dereferenzierte Zeiger. (Hierzu zählen auch die Konstanten, denn ihre Initialisierung hat ja ebenfalls die Form einer Anweisung. Man nennt sie auch unveränderliche L-Werte.) In den Sprachregeln ist für die einzelnen Operatoren festgelegt, ob sie L-Werte als Operanden erfordern bzw. als Ergebnis wieder einen L-Wert liefern.

Priorität (Vorrang) Bearbeiten

Das bekannteste Beispiel einer Prioritätsregel (priority rule) ist die Rechenvorschrift „Punkt vor Strich“. Analog dazu legt C++ für alle Operatoren fest, wie stark sie ihre Operanden „an sich binden“, d.h. wie ein Ausdruck syntaktisch gruppiert wird. Z.B. binden die Vergleichsoperatoren stärker als die logischen Operatoren UND und ODER. a<b && c<d bedeutet daher dasselbe wie (a<b) && (c<d).

Siehe auch: Liste der Operatoren nach Priorität

Assoziativität Bearbeiten

Bei einer Kette von Operatoren gleicher Priorität entscheiden die Assoziativitätsregeln. Die arithmetischen Operatoren gruppieren von links nach rechts, d.h. a - b - c bedeutet dasselbe wie (a - b) - c und nicht etwa a - (b - c). Dagegen gruppieren die Zuweisungsoperatoren von rechts nach links: Im Ausdruck

a *= b = 5;

wird zuerst b = 5 zugewiesen und dann a mit diesem Wert multipliziert.

Auswertungsreihenfolge Bearbeiten

Durch Priorität und Assoziativität wird aber nicht vollständig festgelegt, wie die Berechnungen tatsächlich nacheinander ablaufen! Im Codeausschnitt

int f(int);
int g(int);

int x = f(1) + g(2);

Ist nicht garantiert, dass die beiden Funktionsaufrufe in einer bestimmten Reihenfolge geschehen. Bei „simplen“ Funktionen macht das zwar keinen Unterschied. Denken Sie aber an Funktionen f und g, die auf gemeinsame globale Variablen zugreifen und diese auch verändern. Dann ist es sehr wohl von Bedeutung, welche Funktion zuerst ausgeführt wird. Konstrukte, die sich auf eine bestimmte Auswertungsreihenfolge verlassen, sollten Sie unter allen Umständen vermeiden. Wenn es mit einem Compiler gutgeht, können Sie daraus keine Schlüsse auf andere Compiler ziehen! Eine „sichere“ Formulierung des Beispiels wäre:

int x1 = f(1);
int x2 = g(2);
int x = x1 + x2;

Dasselbe gilt für die Reihenfolge, in der die Argumente einer Funktion ermittelt werden. Bei

int x = h(f(1), g(2));

wird je nach Compiler zuerst f(1) oder zuerst g(2) berechnet oder gar beides gleichzeitig (etwa auf einer Mehr-CPU-Maschine).