C++ Tutorial

 Operatoren

Allgemein gilt: Operatoren können nur Operanden mit gleichen Datentypen verarbeiten. Sind die Datentypen nicht identisch, werden sie auf einen gemeinsamen Datentyp konvertiert. Mehr zur Typkonvertierung später.

Zuweisungsoperator

Zuweisung von numerischen Daten

Die Zuweisung eines Datums oder eines Ausdrucks an eine Variable erfolgt mit dem Zuweisungsoperator =. Dabei können folgende Fälle auftreten:

Datentypen links und rechts des Operators sind gleich

In diesem Fall erfolgt die Zuweisung 1:1 ohne Informationsverlust.

Linker Operand besitzt größeren Wertebereich als rechter Operand und beide Datentypen besitzen den gleichen Vorzeichentyp (signed/unsigned)

Der rechte Operand wird vorzeichenrichtig auf den Datentyp des linken Operanden erweitert.

Linker Operand besitzt kleineren Wertebereich als rechter Operand oder ein Datentyp ist vorzeichenbehaftet und der andere vorzeichenlos

Es werden nur die niederwertigen Bytes der rechten Operanden in den linken Operanden übernommen, d. h., es können Informationen verloren gehen.

Linker Operand ist ein Ganzzahl-Datentyp und rechter Operand ist ein Gleitkomma-Datentyp

Bei der Konvertierung einer Gleitkommazahl in eine Ganzzahl werden die Nachkommastellen abgeschnitten, es erfolgt keine Rundung.

preventing narrowing

Soll sichergestellt werden, dass bei einer Zuweisung keine Information verloren geht, ist der Ausdruck rechts vom Zuweisungsoperator in eine geschweifte Klammer einzuschließen. In diesem Fall prüft der Compiler, ob der Ausdruck ohne Informationsverlust zugewiesen werden kann und gibt ansonsten eine Fehlermeldung aus. Diese Überprüfung zur Compilezeit wird als preventing narrowing bezeichnet.

// Header-Dateien einbinden
#include <iostream>
#include <format>

int main()
{
   // Variablen definieren
   unsigned short toAssign = 0xba94;
   float fvar = 1.23f;
   unsigned char ucvar;
   short svar;
   unsigned short usvar;
   unsigned long ulvar;

   // Zuweisungen testen
   // unsigned short = unsigned short
   usvar = toAssign;
   std::cout << std::format("ushort = ushort: {:#x}\n", usvar);
   // unsigned long = unsigned short
   ulvar = toAssign;
   std::cout << std::format("ulong = ushort: {:#x}\n", ulvar);
   // unsigned char = unsigned short
   ucvar = toAssign;
   std::cout << std::format("uchar = ushort: {:#x}\n", ucvar);
   // short = unsigned short
   svar = toAssign;
   std::cout << std::format("short = ushort: {:#x}\n", svar);
   // short = float
   svar = fvar;
   std::cout << std::format("short = float: {}\n", svar);
   // Prevent narrowing
   // svar = usvar; // Zuweisung ok?!
   // svar = { usvar }; // Zuweisung erzeugt Fehler!
}

Zuweisung von Zeichen- und String-Literalen

Wird ein Zeichen-Literal einer Variable zugewiesen, sollte die Variable vom Datentyp char sein.

Bei der Zuweisung eines String-Literals an eine Variable muss die Variable den Datentyp Zeiger auf const char besitzen. Um einen const char-Zeiger zu definieren, wird nach dem Datentyp const char und vor dem Variablennamen ein * (Sternchen) gestellt.

// Header-Dateien einbinden
#include <iostream>
#include <format>

int main()
{
   // char- und Variablen definieren
   char cvar1, cvar2;
   // Daten zuweisen
   cvar1 = 'A';    // Buchstabe A
   cvar2 = '\n';   // Linefeed
   // char-Daten ausgeben
   std::cout << std::format("{}{}", cvar1, cvar2);
   // const char-Zeiger definieren
   const char* pstr1;
   // String zuweisen
   pstr1 = "Ich bin ein String!\n";
   // String ausgeben
   std::cout << pstr1;
}

Mehrfach-Zuweisung

Bei der Mehrfach-Zuweisung wird mehreren Variablen in einer Anweisung der gleiche Wert zugewiesen. Die einzelnen Variablen werden mit dem Zuweisungsoperator verkettet und rechts wird der zuzuweisende Ausdruck angegeben. Die Zuweisungen erfolgen in der Reihenfolge von rechts nach links.

int main()
{
   // Variablendefinitionen
   short sVar1, sVar2;
   char cVar;

   // Zuweisungen
   sVar1 = sVar2 = 0xFF;  // Ergebnis: sVar2=255, sVar1=255
   sVar1 = cVar = 0xFF;   // Ergebnis: cVar=-1, sVar1=-1
   cVar = sVar1 = 0xFF;   // Ergebnis: sVar1=255, cVar=-1!
}

Rechenoperationen

Für Berechnungen stehen die Rechenoperationen Addition +, Subtraktion -, Multiplikation * und Division / zur Verfügung. Diese Operationen sind sowohl auf Integer- wie auch auf Gleitkomma-Daten anwendbar. Ferner steht für Integer-Daten noch der Modulo-Operator % zur Verfügung, der den Rest einer Division berechnet. Bei allen Operationen gilt: Punkt- vor Strichrechnung.

Beachten Sie, dass eine Division von zwei Integer-Daten als Ergebnis ebenfalls ein Integer-Datum liefert. Soll das Ergebnis ein Gleitkomma-Datum sein, muss vor der Division eine Typkonvertierung durchgeführt werden (wird in einem weiteren Kapitel erläutert).

#include <iostream>
#include <format>

int main()
{
   // int-Variablen definieren/initalisieren
   int ivar1 = 10, ivar2 = 3;
   // int-Division berechnen
   auto res1 = ivar1 / ivar2;
   // Rest einer int-Division berechnen
   auto res2 = ivar1 % ivar2;
   // Ergebnisse ausgeben
   std::cout << std::format("10 / 3 = {}\n10 % 3 = {}\n", res1, res2);
}

Kurzschreibweisen

Für häufig benötigte Rechenoperationen stellt C++ eine Reihe von Kurzschreibweisen bereit, die in der nachfolgenden Tabelle aufgeführt sind.

Operator
Rechenoperation
x++
Erhöht x um 1 nach dessen Auswertung
++x
Erhöht x um 1 vor dessen Auswertung
x--
Vermindert x um 1 nach dessen Auswertung
--x
Vermindert x um 1 vor dessen Auswertung
x += y
x = x + y
x -= y
x = x - y
x *= y
x = x * y
x /= y
x = x / y
x %= y
x = x % y

#include <iostream>
#include <format>

int main()
{
   // Zwei int-Variablen definieren/initialisieren
   int var1 = 11, var2 = 3;
   // var1 inkrementieren
   var1++;
   // var1 durch var2 dividieren
   var1 /= var2;
   // var1 ausgeben
   std::cout << std::format("var1: {}\n", var1);
   // var2++ var1 zuweisen
   var1 = var2++;
   std::cout << std::format("var1: {}, var2: {}\n", var1, var2);
   // ++var2 var1 zuweisen
   var1 = ++var2;
   std::cout << std::format("var1: {}, var2: {}\n", var1, var2);
}

Bit- und Schiebeoperationen

Bit- und Schiebeoperationen sind nur für Integer-Daten zugelassen. Mit ihnen können 8, 16, 32 oder 64 Bits gleichzeitig beeinflusst werden, abhängig davon, auf welchen Datentyp die Operation angewandt wird. Bis auf den Bitoperator 'rechts schieben' arbeiten alle Bit- und Schiebeoperatoren vorzeichenunabhängig. Bei all diesen Operationen wird das Datum als eine Kombination aus '0' und '1' Bits betrachtet.

Operator
Syntax
Ergebnis
&
OP1 & OP2
AND: Liefert als Ergebnis nur an den Stellen ein 1-Bit, an denen beide Operanden ein 1-Bit besitzen.
|
OP1 | OP2
OR: Liefert als Ergebnis an den Stellen ein 1-Bit, an denen einer der Operanden ein 1-Bit besitzen.
^
OP1 ^ OP2
XOR: Liefert als Ergebnis an den Stellen ein 1-Bit, an denen beide Operanden unterschiedliche Bits besitzen
~
~OP1
NOT: Liefert an den Stellen ein 1-Bit, an denen der Operand ein 0-Bit besitzt und umgekehrt.
<<
OP1 << OP2
SHIFT LEFT: Schiebt die Bits des Operanden OP1 um OP2 Positionen nach links.
>>
OP1 >> OP2
SHIFT RIGHT: Schiebt die Bits des Operanden OP1 um OP2 Positionen nach rechts.

Genauso wie bei den Grundrechenoperationen stehen auch für die Bit- und Schiebeoperationen entsprechende Kurzschreibweisen zur Verfügung:

Operator
Operation
x &= y
x = x & y
x |= y
x = x | y
x ^= y
x = x ^ y
x <<= y
x = x << y
x >>= y
x = x >> y

#include <iostream>
#include <format>

int main()
{
   // Zwei Variablen definieren
   unsigned short var1 = 0xaa55, var2 = 0x00ff;
   // Inhalt der Variablen als Hex-Zahlen ausgeben
   std::cout << std::format("Als Hex-Zahlen var1: {:#06x}, var2: {:#06x}\n", var1, var2);
  // Verunden der beiden Variablen
   std::cout << std::format("var1 & var2: {:#06x}\n", var1 & var2);
   // XOR der beiden Variablen
   std::cout << std::format("var1 ^ var2: {:#06x}\n", var1 ^ var2);
   // var1 um 4 Bits nach links
   var1 <<= 4;
   std::cout << std::format("var1 <<= 4: {:#06x}\n", var1);
   // var2 um 4 Bits nach rechts
   var2 >>= 4;
   std::cout << std::format("var2 >>= 4: {:#06x}\n", var2);
}

Vergleichs- und Logikoperationen

Die Vergleichs- und Logikoperatoren werden hauptsächlich in Verzweigungen und Programmschleifen eingesetzt, die später behandelt werden. Beide Operatorgruppen liefern als Ergebnis der Operation den bool-Wert true oder false zurück.

C++ interpretiert bei Vergleichsoperationen einen numerischen Wert ungleich 0 als true und den Wert 0 als false.

Operator
Syntax
Operation
<
EXP1 < EXP2
true, wenn Ergebnis von Ausdruck EXP1 kleiner als Ergebnis von Ausdruck EXP2
<=
EXP1 <= EXP2
true, wenn Ergebnis von Ausdruck EXP1 kleiner oder gleich Ergebnis von Ausdruck EXP2
==
EXP1 == EXP2
true, wenn Ergebnis von Ausdruck EXP1 gleich Ergebnis von Ausdruck EXP2
!=
EXP1 1= EXP2
true, wenn Ergebnis von Ausdruck EXP1 ungleich Ergebnis von Ausdruck EXP2
>= 
EXP1 >= EXP2
true, wenn Ergebnis von Ausdruck EXP1 größer oder gleich Ergebnis von Ausdruck EXP2
>
EXP1 > EXP2
true, wenn Ergebnis von Ausdruck EXP1 größer als Ergebnis von Ausdruck EXP2
&&
EXP1 && EXP2
true, wenn Ergebnis von Ausdruck EXP1 und EXP2 gleich true
||
EXP1 || EXP2
true, wenn Ergebnis von Ausdruck EXP1 oderEXP2 gleich true
!
! EXP
true, wenn Ergebnis von Ausdruck EXP false ist

#include <iostream>
#include <format>

int main()
{
   // Variablen definieren
   short var1 = 10, var2 = 5;
   std::cout << std::format("var1, var2: {},{}\n", var1, var2);
   // Vergleichsoperationen
   // Klammern wegen der besseren Lesbarkeit
   auto res = (var1 < var2);
   std::cout << std::format("var1 < var2: {}\n", res);
   // Logikoperationen
   res = ((var1 == 10) && (var2 == 2));
   std::cout << std::format("(var1 == 10) && (var2 == 2): {}\n", res);
   res = ((var1 > 5) || (var2 >= 10));
   std::cout << std::format("(var1 > 5) || (var2 >= 10): {}\n", res);
}

Rangfolge der Operatoren

Nachfolgend in tabellarischer Form die Rangfolge aller Operatoren. In der Tabelle gilt: Operatoren in der Gruppe 1 werden vor den Operatoren der Gruppe 2 ausgeführt usw. Durch entsprechendes Setzen von Klammern kann die Reihenfolge der Operationen abgeändert werden.

Gruppe
Operator
Operation
1
::
Zugriffsoperator
2
(...)
Funktionsaufruf
[...]
Indizierung

->
Indirekter Zugriff auf Member

.
Direkter Zugriff auf Member

++ und --
Post-Inkrement/Dekrement

DTYP(...)
Typkonvertierung
3
! und ~
NOT und Negation
+ und -
Vorzeichen
++ und ++
Pre-Inkerement/Dekrement
&
Adressoperator
*
Dereferenzierungsoperator
sizeof
Belegter Speicherplatz (Bytes)
new und delete
Dynamische Speicherverwaltung
DTYP (...)
Typkonvertierung
co_wait
Coroutine unterbrechen
4
.* und ->*
Indirekter Zugriff auf Member
5
* und / und %
Arithmetische Operatoren
6
+ und -
Arithmetische Operatoren
7
<< und >>
Scheibeoperatoren
8
<=>
3-Wege-Vergleichsoperator
9
<= und <
Vergleichsoperatoren
>= und >
Vergleichsoperatoren
10
== und !=
Vergleichsoperatoren
11
&
UND Bitoperator
12
^
XOR-Bitoperator
13
|
ODER Bitoperator
14
&&
logischer UND-Operator
15
||
logischer ODER-Operator
16
?..:
Bedingungsoperator
= und *=
/= und +=
%= und +=
-= und &=
^= und <<=
>>=
Zuweisungsoperatoren
throw
Ausnahme auslösen
co_yield
Coroutine unterbrechen
17
,
Komma-Operator

Copyright 2021 © Wolfgang Schröder
Impressum & Datenschutz