C++-Programmierung/ Einführung in C++/ Variablen, Konstanten und ihre Datentypen
Variablen sind Behälter für Werte, sie stellen gewissermaßen das Gedächtnis eines Programms bereit. Konstanten sind spezielle Variablen, sie ändern ihren Wert nie. Der Datentyp einer Variablen oder Konstanten beschreibt, wie der Inhalt zu verstehen ist.
Ein Rechner kennt nur zwei Grundzustände: 0 und 1. Durch eine Aneinanderreihung solcher Zustände lassen sich mehr verschiedene Werte darstellen. Mit acht aufgereihten Zuständen (= 8 Bit = 1 Byte) lassen sich bereits 256 verschiedene Werte darstellen. Diese Werte kann man beispielsweise als Ganzzahl, (Schrift-)Zeichen, Wahrheitswert oder Gleitkommazahl interpretieren. Der Datentyp gibt daher Auskunft darüber, um was es sich handelt.
Der C++-Standard schreibt nicht vor, dass ein Byte aus genau 8 Bit bestehen muss – diese Anzahl ist jedoch weitverbreitet. Es ist also möglich, dass auf einer speziellen Prozessorarchitektur z. B. eine Anzahl von 10 Bit als „ein Byte“ festgelegt ist. Dies ist jedoch äußerst selten der Fall, daher werden wir im Folgenden annehmen, dass ein Byte aus 8 Bit besteht.
Datentypen
[Bearbeiten]Zunächst sollen die Datentypen von C++ beschrieben werden, denn sie sind grundlegend für eine Variable oder Konstante. Die vier wichtigsten (Gruppen von) Datentypen sind: Wahrheitswerte, Zeichen, Ganzzahlen und Gleitkommazahlen.
Wahrheitswerte
[Bearbeiten]Der Datentyp für Wahrheitswerte heißt in C++ bool
, was eine Abkürzung für boolean ist. Er kann nur zwei Zustände annehmen: true
(wahr) oder false
(falsch). Obwohl eigentlich 1 Bit ausreichen würde, hat bool
mindestens eine Größe von einem Byte (also 8 Bit), denn 1 Byte ist die kleinste adressierbare Einheit und somit die Minimalgröße für jeden Datentyp. Es ist auch durchaus möglich, dass ein bool
beispielsweise 4 Byte belegt, da dies auf einigen Prozessorarchitekturen die Zugriffsgeschwindigkeit erhöht.
Zeichen
[Bearbeiten]Zeichen sind eigentlich Ganzzahlen. Sie unterscheiden sich von diesen nur bezüglich der Ein- und Ausgabe. Jeder Zahl ist ein Zeichen zugeordnet. Mit den Zahlen lässt sich ganz normal rechnen aber bei der Ausgabe erscheint das zugeordnete Zeichen auf dem Bildschirm. Welches Zeichen welcher Zahl entspricht, wird durch den verwendeten Zeichensatz festgelegt.
Die meisten Zeichensätze beinhalten den sogenannten ASCII-Code (American Standard Code for Information Interchange), welcher die Zeichen 0 – 127 belegt. Er enthält 32 Steuerzeichen (0 – 31) und 96 druckbare Zeichen (32 – 127).
char
ist der Standard-Datentyp für Zeichen. Er ist in der Regel 1 Byte groß und kann somit 256 verschiedene Zeichen darstellen. Diese genügen für einen erweiterten ASCII-Code, welcher zum Beispiel auch deutsche Umlaute definiert. Für Unicode-Zeichen gibt es die Datentypen char16_t
mit einer Größe von 2 Byte und char32_t
mit einer Größe von 4 Byte. Früher nutzte man für Unicode auch den Datentyp wchar_t
, welcher je nach System 2 oder 4 Byte groß war. Dieser Datentyp sollte jedoch nicht mehr eingesetzt werden. Die folgende Liste enthält einige nützliche Links zu Artikeln der Wikipedia:
- ASCII
- Unicode (UTF-8, UTF-16, UTF-32)
- ISO 8859-1 (Latin-1)
- Codepage 437 (DOS / DOS-Box)
Es gibt in C++ 4 eingebaute Datentypen für Zeichen:
char
char16_t
char32_t
wchar_t
(veraltet)
Ganzzahlen
[Bearbeiten]C++ definiert folgende eingebaute Datentypen für Ganzzahlen:
Schreibweise | Typ | Anzahl Bits nach data model | ||||
---|---|---|---|---|---|---|
C++ standard | LP32 | ILP32 | LLP64 | LP64 | ||
signed char
|
signed char
|
mindestens 8 |
8 | 8 | 8 | 8 |
unsigned char
|
unsigned char
| |||||
short
|
short
|
mindestens 16 |
16 | 16 | 16 | 16 |
short int
| ||||||
signed short
| ||||||
signed short int
| ||||||
unsigned short
|
unsigned short
| |||||
unsigned short int
| ||||||
int
|
int
|
mindestens 16 |
16 | 32 | 32 | 32 |
signed
| ||||||
signed int
| ||||||
unsigned
|
unsigned
| |||||
unsigned int
| ||||||
long
|
long
|
mindestens 32 |
32 | 32 | 32 | 64 |
long int
| ||||||
signed long
| ||||||
signed long int
| ||||||
unsigned long
|
unsigned long
| |||||
unsigned long int
| ||||||
long long
|
long long
|
mindestens 64 |
64 | 64 | 64 | 64 |
long long int
| ||||||
signed long long
| ||||||
signed long long int
| ||||||
unsigned long long
|
unsigned long long
| |||||
unsigned long long int
|
Alle Schreibweisen sind identisch zu dem jeweils zugeordneten Typ. Die Schreibweise, die in der Typ-Spalte verwendet wird, ist die in diesem Buch genutzte Schreibweise. In der Praxis finden sie aber, je nachdem wer den Code geschrieben hat, auch die äquivalenten Schreibweisen der ersten Spalte.
Die genaue Anzahl der Bits hängt von der Implementierung ab und wird gemeinhin als data model bezeichnet. Vier data models sind weit verbreitet:
- 32 Bit Systeme
- LP32 oder 2/4/4 (
int
hat 16 Bits,long
und Zeiger haben 32 Bits)- Win16 API
- ILP32 oder 4/4/4 (
int
,long
und Zeiger haben 32 Bits)- Win32 API
- Unix und Unixoide Systeme (Linux, Mac OS X)
- LP32 oder 2/4/4 (
- 64 Bit Systeme
- LLP64 oder 4/4/8 (
int
undlong
haben 32 Bits, Zeiger haben 64 Bits)- Win64 API
- LP64 oder 4/8/8 (
int
hat 32 Bits,long
und Zeiger haben 64 Bits)- Unix und Unixoide Systeme (Linux, Mac OS X)
- LLP64 oder 4/4/8 (
Der Wertebereich von vorzeichenbehafteten Typen (»signed
«) berechnet sich durch:
Für vorzeichenlose Typen (»unsigned
«) berechnet er sich durch:
Auffällig sind in der Tabelle die beiden char
-Datentypen. Im Gegensatz zu den anderen Datentypen gibt es hier keine Schreibweise, in der am Ende ein int
steht. Und was noch wichtiger ist, signed char
darf nicht mit char
abgekürzt werden! Das liegt daran, dass char
ein Datentyp für Zeichen ist, während signed char
und unsigned char
üblicherweise Zahlen repräsentieren. Historisch bedingt ist die Trennung zwischen Zeichen und Zahlen in C++ leider sehr unsauber, was sich vor allem bei den char
-Datentypen zeigt.
Sowohl signed char
, als auch unsigned char
werden bei der Ein- und Ausgabe als Zeichen behandelt, weshalb hier immer zuvor nach int
gecasted (umgewandelt, Näheres im Kapitel Casts) werden muss. Der Datentyp char
kann vom Wertebereich her je nach Compiler entweder zu signed char
oder zu unsigned char
identisch sein. Zu beachten ist jedoch, dass char
dennoch ein eigenständiger Typ ist! Für den Augenblick ist diese Unterscheidung nicht so wichtig, wir werden jedoch noch einmal auf dieses (im Kontext von Templates wichtige) Detail zu sprechen kommen.
Für den Augenblick sollten Sie sich merken: Wenn Sie eine Zahl mit einer 1-Byte-Variablen repräsentieren wollen, dann nutzen Sie signed char
oder unsigned char
, wenn Sie ein Zeichen repräsentieren wollen, verwenden Sie char
.
Wählen Sie ein int
, wenn dieser Typ alle Zahlen des nötigen Wertebereichs aufnehmen kann, bei vorzeichenlosen Zahlen verwenden Sie unsigned
. Reicht dieser Wertebereich nicht aus und ist long
größer, dann nehmen Sie long
(bzw. unsigned long
). short
und unsigned short
sollte nur Verwendung finden, wenn Speicherplatz knapp ist, etwa bei Verwendung großer Arrays, oder wenn Low-Level-Datenstrukturen festgelegter Größe benutzt werden müssen. Achten Sie darauf, dass der theoretisch größte Wert, welcher für Ihre Variable auftreten könnte, den größten möglichen Wert nicht überschreitet. Selbiges gilt natürlich auch für die Unterschreitung des kleinstmöglichen Wertes.
Ein Unter- oder Überlauf ist übrigens durchaus möglich. Die meisten Compiler bieten zwar eine Option an, um in einem solchen Fall einen Fehler zu erzeugen, aber diese Option ist standardmäßig nicht aktiv. Im folgenden kleinen Beispiel werden die Datentypen short
(min: -32768, max: 32767) und unsigned short
benutzt und bei beiden wird je ein Unter- und ein Überlauf ausgeführt:
Davon ausgehend, dass short
eine Größe von 2 Byte hat, finden je zwei Über- bzw. Unterläufe statt.
#include <iostream>
int main(){
short variable1 = 15000;
unsigned short variable2 = 15000;
std::cout << "short Variable: " << variable1 << std::endl
<< "unsigned short Variable: " << variable2 << std::endl
<< "+30000\n\n";
variable1 += 30000;
variable2 += 30000;
std::cout << "short Variable: " << variable1 << " (Überlauf)" << std::endl
<< "unsigned short Variable: " << variable2 << std::endl
<< "+30000\n\n";
variable1 += 30000;
variable2 += 30000;
std::cout << "short Variable: " << variable1 << std::endl
<< "unsigned short Variable: " << variable2 << " (Überlauf)" << std::endl
<< "-30000\n\n";
variable1 -= 30000;
variable2 -= 30000;
std::cout << "short Variable: " << variable1 << std::endl
<< "unsigned short Variable: " << variable2 << " (Unterlauf)" << std::endl
<< "-30000\n\n";
variable1 -= 30000;
variable2 -= 30000;
std::cout << "short Variable: " << variable1 << " (Unterlauf)" << std::endl
<< "unsigned short Variable: " << variable2 << std::endl;
}
short Variable: 15000
unsigned short Variable: 15000
+30000
short Variable: -20536 (Überlauf)
unsigned short Variable: 45000
+30000
short Variable: 9464
unsigned short Variable: 9464 (Überlauf)
-30000
short Variable: -20536
unsigned short Variable: 45000 (Unterlauf)
-30000
short Variable: 15000 (Unterlauf)
unsigned short Variable: 15000
Verständlicher wird dieses Phänomen, wenn man die Zahlen binär (Duales Zahlensystem) darstellt. Der Einfachheit halber beginnen wir mit der Darstellung der unsigned short
Variablen, die ersten beiden Additionen von jeweils 30000:
Addition im Dualsystem mit unsigned short
als Datentyp
Rechnung 1
|0011101010011000| 15000
+ |0111010100110000| 30000
--------------------------------
Merker |111 11 |
--------------------------------
= |1010111111001000| 45000
Rechnung 2
|1010111111001000| 45000
+ |0111010100110000| 30000
--------------------------------
Merker 1|1111111 |
--------------------------------
= 1|0010010011111000| 9464
Die beiden Rechnungen weisen keinerlei Besonderheiten auf. Da nur die letzten 16 Ziffern beachtet werden (2 Byte = 16 Bit), entfällt in der zweiten Rechnung die 1 vor dem Vertikalstrich, wodurch das Ergebnis (in dezimaler Schreibweise) 9464 und nicht 75000 lautet.
Anschließend werden von der unsigned short
-Ganzzahl zwei Mal jeweils 30000 subtrahiert:
Subtraktion im Dualsystem mit unsigned short
als Datentyp
Rechnung 3
|0010010011111000| 9464
- |0111010100110000| 30000
----------------------------------
Merker...1|1111111 |
----------------------------------
=...1|1010111111001000| 45000
Rechnung 4
|1010111111001000| 45000
- |0111010100110000| 30000
----------------------------------
Merker |111 11 |
----------------------------------
= |0011101010011000| 15000
In diesem Fall ist die zweite Rechnung unauffällig. In der ersten Rechnung wird hingegen eine große Zahl von einer kleineren abgezogen, was zu einem negativen Ergebnis führt – oder besser – führen würde, denn die Untergrenze ist in diesem Fall 0. Dort wo die 3 Punkte stehen, folgt eine unendliche Anzahl von Einsen. Dies ist keineswegs nur bei Dualzahlen der Fall. Wenn Sie im dezimalen System eine große Zahl von einer kleineren nach den üblichen Regeln der schriftlichen Subtraktion abziehen, so erhalten Sie ein ähnliches Ergebnis:
24 - 31 ------------ Merker...1 ------------ =...993
Im Programm werden mit der Vorzeichen-behafteten Ganzzahl, der short
-Variablen, ebenfalls vier Rechnungen durchgeführt. Deren duale Darstellung wird Ihnen sehr bekannt vorkommen:
Addition im Dualsystem mitshort
als Datentyp Rechnung 1 |0|011101010011000| 15000 + |0|111010100110000| 30000 -------------------------------- Merker |1|11 11 | -------------------------------- = |1|010111111001000| -20536 Rechnung 2 |1|010111111001000| -20536 + |0|111010100110000| 30000 -------------------------------- Merker 1|1|111111 | -------------------------------- = 1|0|010010011111000| 9464 Subtraktion im Dualsystem mitshort
als Datentyp Rechnung 3 |0|010010011111000| 9464 - |0|111010100110000| 30000 ---------------------------------- Merker...1|1|111111 | ---------------------------------- =...1|1|010111111001000| -20536 Rechnung 4 |1|010111111001000| -20536 - |0|111010100110000| 30000 ---------------------------------- Merker |1|11 11 | ---------------------------------- = |0|011101010011000| 15000
Die dualen Ziffern sind die gesamte Zeit über exakt die gleichen, der einzige Unterschied besteht darin, dass negative Zahlen in Zweierkomplement-Darstellung repräsentiert werden. Dies führt zu einer veränderten Darstellung im Dezimalsystem.
Meist ist es besser, wenn man die genaue Größe der Datentypen festlegt. Hierfür muss der Header cstdint
eingebunden werden. Darin sind Alias-Namen für die eingebauten Datentypen definiert:
std::int8_t
optionalstd::int16_t
optionalstd::int32_t
optionalstd::int64_t
optionalstd::int_fast8_t
std::int_fast16_t
std::int_fast32_t
std::int_fast64_t
std::int_least8_t
std::int_least16_t
std::int_least32_t
std::int_least64_t
std::intmax_t
std::intptr_t
optionalstd::uint8_t
optionalstd::uint16_t
optionalstd::uint32_t
optionalstd::uint64_t
optionalstd::uint_fast8_t
std::uint_fast16_t
std::uint_fast32_t
std::uint_fast64_t
std::uint_least8_t
std::uint_least16_t
std::uint_least32_t
std::uint_least64_t
std::uintmax_t
std::uintptr_t
optional
Alle Datentypen, die mit int
beginnen, stehen für signed
Datentypen, alle, die mit uint
beginnen, für unsigned
Datentypen. Die mit »optional« gekennzeichneten Datentypen sind nur definiert, wenn sie durch die Plattform auch nativ unterstützt werden. Dies ist jedoch auf den schon oben referenzierten Systemen immer der Fall. Lediglich auf Mikrocontrollern oder ähnlichem kann es hier zu Problemen kommen.
Die least
-Datentypen entsprechen dem kleinsten Typ, der mindestens so viele Bits hat, die fast
-Datentypen dem schnellsten Datentyp, der mindestens so viele Bits hat. Die max
-Datentypen entsprechen dem jeweils größten verfügbaren Datentyp. Die ptr
-Datentypen haben exakt so viele Bit wie ein Zeiger (siehe Kapitel Zeiger) und sind daher ebenfalls nur verfügbar, wenn die Hardware einen entsprechenden Integer-Datentyp nativ unterstützt.
In der Regel ist es am sinnvollsten die exakten Datentypen zu verwenden, also etwa std::uint16_t
, wenn man einen Datentyp möchte, der 16 Bit hat und vorzeichenlos ist. Die fast
-Datentypen können nötigenfalls zur Geschwindigkeitsoptimierung innerhalb von Funktionen eingesetzt werden.
Gleitkommazahlen
[Bearbeiten]Eine Gleitkommavariable kann sich eine bestimmte Anzahl Ziffern merken und dazu die Position des Kommas. Das Wissen über den internen Aufbau einer solchen Zahl werden Sie wahrscheinlich eher selten bis nie brauchen, daher sei an dieser Stelle auf den Wikipediaartikel über Gleitkommazahlen verwiesen. In C++ werden Sie Gleitkommazahlen/-variablen für das Rechnen mit Kommazahlen verwenden. Es gibt drei Datentypen für Gleitkommazahlen, die in der folgenden Tabelle mit ihren üblichen Werten aufgelistet sind:
Typ | Speicherplatz | Wertebereich | kleinste positive Zahl | Genauigkeit |
---|---|---|---|---|
float |
4 Byte | 6 Stellen | ||
double |
8 Byte | 12 Stellen | ||
long double |
10 Byte | 18 Stellen |
Die Auswahl eines Gleitkommadatentyps ist weniger einfach als die einer Ganzzahl. Wenn Sie nicht genau wissen, was Sie nehmen sollen, ist double
in der Regel eine gute Wahl. Sobald Sie erst einmal ausreichend Erfahrung haben, wird es Ihnen leichter fallen abzuschätzen, ob float
oder long double
für Ihr Problem vielleicht eine bessere Wahl ist.
Variablen
[Bearbeiten]Bevor eine Variable verwendet werden kann, muss sie dem Compiler bekannt gegeben werden. Dies bezeichnet man als Deklaration der Variablen. Das eigentliche Anlegen einer Variablen, so dass der Compiler Speicherplatz für sie reserviert, wird Definition genannt. Eine Definition ist immer auch eine Deklaration und bei Variablen ist der Unterschied zwischen Deklaration und Definition etwas zu kompliziert, um ihn an dieser Stelle bereits zu erklären. Sie werden die Begriffe zunächst in Zusammenhang mit Funktionen kennenlernen und später auch für Variablen. Sie sollten sich jedoch jetzt bereits merken, dass es sich beim Anlegen der Variablen, die wir verwenden, immer um Definitionen handelt. Dies ist insofern wichtig, als dass eine Definition immer nur einmal geschrieben werden darf, während eine Deklaration beliebig oft vorgenommen werden kann. Um einen Vergleich zur realen Welt zu ziehen, wollen wir das Entstehen neuen Lebens betrachten. Sie können beliebig oft erzählen, dass ein bestimmtes Kind geboren wird. Tatsächlich geschehen kann dies aber nur einmal. Im vorherigen Kapitel haben wir bereits mit Variablen vom Typ int
gerechnet. Nun sollen Sie lernen, wie Variablen in C++ angelegt werden. Die allgemeine Syntax lautet:
Außerdem ist es möglich, mehrere Variablen des gleichen Typs hintereinander anzulegen:
Auch kann man einer Variablen einen Anfangswert geben, dies bezeichnet man als Initialisierung. Es gibt zwei syntaktische Möglichkeiten (Schreibweisen) für Initialisierungen, welche anhand einer int
Variable gezeigt werden soll:
Die erste Variante ist weit verbreitet aber nicht zwingend besser. Bei den fundamentalen Datentypen von C++ spielt es keine Rolle, welche Variante Sie verwenden, aber bei komplexeren Datentypen (Klassen) kann es zu Verwechslungen mit dem Zuweisungsoperator kommen, wenn Sie Möglichkeit 1 benutzen. Den genauen Unterschied zwischen einer Initialisierung und einer Zuweisung werden Sie kennenlernen, sobald es um Klassen geht. Für den Moment sollten Sie sich für eine der beiden Varianten entscheiden. Für Möglichkeit 1 spricht die große Verbreitung und die damit verbundene intuitive Nutzung. In diesem Buch werden wir diese erste Methode verwenden und in Zusammenhang mit Klassen auch eine Empfehlung geben, wann diese Methode zur besseren Übersicht im Quellcode beitragen kann. Für Möglichkeit 2 spricht hingegen, dass diese Syntax für Initialisierungen immer gültig ist. Nebenbei wird bei dieser Methode deutlich, dass es sich um eine Initialisierung handelt.
Variablen mit Anfangswerten können natürlich auch hintereinander angelegt werden, sofern sie den gleichen Datentyp besitzen, allerdings ist davon aus Gründen der Übersichtlichkeit abzuraten.
Wenn Sie einer Variablen keinen Anfangswert geben, müssen Sie ihr später im Programm noch einen Wert zuweisen, bevor Sie mit ihr arbeiten (also damit rechnen oder den Inhalt ausgeben lassen). Weisen Sie einer solchen Variablen keinen Wert zu und benutzen sie, so kann der Inhalt zufällig sein. Genaugenommen handelt es sich dann um die Bitfolge, die an der Stelle im Speicher stand, an der Ihre Variable angelegt wurde. Es gibt in C++ Regeln, in welchen Fällen der Compiler eine Variable ohne explizite Initialisierung implizit mit 0 initialisiert und wann stattdessen einfach der aktuelle Speicherinhalt stehen bleibt. Allerdings sind diese Regeln so kompliziert, dass es sich nicht lohnt, sie sich zu merken. Denn sollte je ein anderer Programmierer Ihren Code lesen, so muss auch dieser die Regeln kennen, um den Code sofort verstehen zu können. Das nachfolgende kleine Programm zeigt einen Fall, in dem C++ besagt, dass keine implizite Initialisierung mit 0 stattfindet.
#include <iostream> // Ein-/Ausgabe
int main(){
int zahl; // Ganzzahlige Variable
double kommazahl1, kommazahl2; // Gleitkommavariablen
char zeichen; // Zeichenvariable
std::cout << "zahl: " << zahl << std::endl // Ausgabe der Werte
<< "kommazahl1: " << kommazahl1 << std::endl // welche jedoch
<< "kommazahl2: " << kommazahl2 << std::endl // nicht festgelegt
<< "zeichen: " << zeichen << std::endl; // wurden
}
zahl: -1211024315
kommazahl1: 4.85875e-270
kommazahl2: -3.32394e-39
zeichen: f
Die Ausgabe kann bei jedem Ausführen des Programms anders lauten. Sollte dies bei Ihnen nicht der Fall sein, so stehen nur zufällig die gleichen Werte an der Stelle im Speicher, welchen die jeweilige Variable belegt. Spätestens nach einem Neustart Ihres Rechners haben Sie höchstwahrscheinlich eine andere Ausgabe. Variablen keinen Anfangswert zu geben, ist beispielsweise sinnvoll, wenn Sie vorhaben, über std::cin
einen Wert in die Variable einzulesen. Dennoch würde es auch in diesem Fall keinen Schaden anrichten, wenn Sie die Variablen explizit mit 0 initialisieren.
#include <iostream> // Ein-/Ausgabe
int main(){
int zahl; // Ganzzahlige Variable
double kommazahl1, kommazahl2; // Gleitkommavariablen
char zeichen; // Zeichenvariable
std::cout << "Geben Sie bitte durch Leerzeichen getrennt eine Ganzzahl, zwei Kommazahlen "
"und ein Zeichen ein:\n";
std::cin >> zahl // Eingabe von Werten
>> kommazahl1 // mit denen die vier
>> kommazahl2 // Variablen gefüllt
>> zeichen; // werden
std::cout << "Zahl: " << zahl << std::endl // Ausgabe der Werte
<< "Kommazahl1: " << kommazahl1 << std::endl // welche zuvor
<< "Kommazahl2: " << kommazahl2 << std::endl // eingegeben
<< "Zeichen: " << zeichen << std::endl; // wurden
}
Geben Sie bitte durch Leerzeichen getrennt eine Ganzzahl, zwei Kommazahlen und ein Zeichen ein:
Benutzereingabe: 6 8.4 6.0 g
Zahl: 6
Kommazahl1: 8.4
Kommazahl2: 6
Zeichen: g
Konstanten
[Bearbeiten]Konstanten sind, wie schon oben beschrieben, Variablen, welche ihren Wert nicht verändern. Daraus folgt, dass einer Konstanten nur genau ein Mal ein Wert zugewiesen werden kann; in C++ muss dies das Initialisieren mit einem Anfangswert sein, andernfalls hätten Sie eine Konstante mit einem zufälligen Wert und das ergibt kaum einen Sinn. Das Schlüsselwort, um eine Variable zu einer Konstanten zu machen, ist const
. Es gehört immer zu dem, was links davon steht, es sei denn, links von ihm steht nichts mehr, dann gehört 'const' zu dem Begriff auf dessen rechter Seite. Dies klingt zwar kompliziert, ist es aber eigentlich gar nicht. Für uns bedeutet es im Moment nur, dass Sie zwei Möglichkeiten haben, eine Variable zu einer Konstanten zu machen:
const int zahl(400); // Alternativ: const int zahl=400;
// oder
int const zahl(400); // Alternativ: int const zahl=400;
Beides hat die gleiche Wirkung, wieder ist die erste Variante weit verbreitet und wieder ist die zweite Variante der besseren Lesbarkeit bei komplexeren Datentypen (Arrays von Zeigern Konstante auf Memberfunktionen…) vorzuziehen. Entscheiden Sie sich für die Variante, die Ihnen besser gefällt und verwenden Sie diese. Wichtig ist, dass Sie der Variante, für die Sie sich entscheiden, treu bleiben, wenigstens für die Dauer eines Projekts. Denn Code, in dem sich der Schreibstil ständig ändert, ist schwieriger zu lesen.
Literale und ihre Datentypen
[Bearbeiten]Ein Literal ist eine Angabe im Quellcode, die einen konkreten Wert angibt und einen der oben beschriebenen Datentypen besitzt.
Bei der Ausgabe ist zu beachten, dass Boolean-Werte als 0 (false) bzw. 1 (true) ausgegeben werden.
Automatische Bestimmung des Datentyps
[Bearbeiten]Da die Bestimmung des Typs für einen ganzzahligen Wert etwas schwieriger ist als bei den übrigen, werden wir diese zuletzt behandeln. Bei Gleitkommaliteralen ist festgelegt, dass es sich um double
-Werte handelt. Um einen Gleitkommaliteral mit einem anderen Typ zu erhalten, ist ein so genanntes Suffix nötig.
Eine Zahl mit Komma (.
) ist also ein double
-Wert. Folgt der Zahl ein f
oder ein F
wird sie zu einem float
-Wert und folgt ihr ein l
oder ein L
wird sie zu einem long double
-Wert. Gleitpunktzahlen können auch in der wissenschaftlichen Schreibweise dargestellt werden.
Wie die letzten beiden Beispiele zeigen, können auch hierbei die Suffixe für den Datentyp genutzt werden.
Um ein Zeichen beziehungsweise eine Zeichenkette als char16_t
bzw. char32_t
zu kennzeichnen, stellt man ein kleines u
bzw. großes U
voran. Für wchar_t
nutzt man ein großes L
.
'a' // char
u'b' // char16_t
U'b' // char32_t
L'b' // wchar_t
"Ich bin ein Text" // char const*
u"Ich bin ein Text" // char16_t const*
U"Ich bin ein Text" // char32_t const*
L"Ich bin ein Text" // wchar_t const*
Was das Sternchen (*
) hinter dem Datentyp im Kommentar bedeutet, werden Sie in einem späteren Kapitel erfahren. bool
kann nur zwei Zustände annehmen, entsprechend gibt es auch nur zwei bool
-Literale: true
und false
.
Nun zu den Ganzzahlen. Neben der dezimalen Darstellung von Zahlen gibt es in C++ auch die Möglichkeit der Binären, Oktalen und Hexadezimalen Darstellung. Um eine Zahl als Binär zu kennzeichnen, wird ein 0b
oder 0B
vorangestellt, für Oktal wird nur eine 0
(Null) vorangestellt und für eine Hexadezimalzahl wird 0x
oder 0X
vorangestellt. Die Groß-/Kleinschreibung der hexadezimalen Ziffern a
bis f
spielt keine Rolle.
756 // Dezimal, Dezimal: 756
0b10 // Binär, Dezimal: 2
0B111 // Binär, Dezimal: 7
046 // Oktal, Dezimal: 38
0757 // Oktal, Dezimal: 495
0xffff // Hexadezimal, Dezimal: 65535
0X1234ABcd // Hexadezimal, Dezimal: 305441741
Der Datentyp wird durch die Größe des Wertes bestimmt, wobei die folgende Reihenfolge gilt: int
, unsigned int
, long
, unsigned long
, long long
, unsigned long long
. Weiterhin kann jeder Ganzzahl auch explizit das Suffix u
oder U
für unsigned
und ein l
oder L
für long
bzw. ein ll
oder LL
für long long
angehängt werden. Die Reihenfolge ändert sich entsprechend den durch die Suffixe festgelegten Kriterien.
übersichtlichere int-Schreibweise
[Bearbeiten]Es ist außerdem möglich, Integer-Literale an beliebigen Stellen durch das Zeichen '
zu trennen, um die Übersicht zu verbessern. Dies kann insbesondere bei binären Literalen nützlich sein, da diese oft sehr lang sind.
9'756'432'108 // ' als Tausender-Trennzeichen
978'3'446'43981'8 // ' als Trennzeichen für eine ISBN-Nummer
0B1111'0000'1010'0101 // ' als Trennzeichen für einen 16 Bit Wert mit 4 Gruppen
Das Wissen über die Datentypen von Literalen werden Sie wahrscheinlich eher selten benötigen, daher reicht es „mal etwas davon gehört zu haben“ und es, wenn nötig, nachzuschlagen.