C++ Tutorial

Konstanten

Konstanten sind Daten, die nach ihrer Definition nicht mehr geändert werden können. Sie können jeden beliebigen Datentyp besitzen.

Literale (unbenannte Konstanten)

Ein Literal ist die Angabe eines Wertes, wie z.B. die Zahl 5 oder 3.14 oder der String "Dies ist ein Literal".

Um die Lesbarkeit von numerischen Literalen zu verbessern, können innerhalb des Literals Hochkomma zur Gruppierung von Ziffern verwendet werden, z.B. 1'000'000.

Integer-Literale

Integer-Literale besitzen standardmäßig den kleinsten Datentyp, in dem ihr Wert repräsentiert werden kann. Dabei wird folgende Reihenfolge durchlaufen: int, long und long long. Eine Ausnahme von dieser Reihenfolge bilden Integer-Literale die in oktaler bzw. hexadezimaler Schreibweise angegeben werden. Hier lautet die Reihenfolge: int, unsigned int, long, unsigned long, long long und unsigned long long. Literale in oktaler Schreibweise werden durch das Präfix 0 (eine Null!), Literale in hexadezimaler Schreibweise durch das Präfix 0x bzw. 0X und binäre Literale durch das Präfix 0b bzw. 0B gekennzeichnet.

Um ein Integer-Literal explizit einem Datentyp zuzuordnen, wird der Wert mit einem Suffix erweitert. Bei diesen Erweiterungen ist die Groß-/Kleinschreibung nicht relevant. Die nachfolgende Tabelle enthält eine Übersicht über die verschiedenen Erweiterungen sowie Beispiele dazu:

Literal, Suffix/Präfix
 
Dezimal-Literal
3
-5
+4
Binär-Literal. Präfix 0b
0b0000'0011
012
0665
Oktal-Literal, Präfix 0
03
-2147483648...2147483647
-2147483648...2147483647
Hex-Literal, Präfix 0x
0x40
-0XFF00
-0xff
unsigned Literal, Suffix U
10U
0xFF00u
012u
long Literal, Suffix U
-10L
0xFF00L
022l
unsgned long Literal, Suffix UL
12UL
0xFFul
021ul
long long Literal, Suffix LL
-10LL
0xfll
-023LL
unsigned long long Literal, Suffix ULL
345UL
0x01ull
0564ULL
size_t (Ergebnis von sizeof), Z UZ
3Z
-5UZ
4z

Gleitkomma-Literale

Gleitkomma-Literale bestehen aus Ziffern und einem Dezimalpunkt. Optional kann ein Gleitkomma-Literal einen Exponenten enthalten.

Standardmäßig sind Gleitkomma-Literale vom Datentyp double. Um einem Gleitkomma-Literal einen von double abweichenden Datentyp zuzuweisen, wird das Literal mit einem Suffix laut nachfolgender Tabelle erweitert. Auch hier spielt die Groß-/Kleinschreibung bei der Erweiterung keine Rolle.

Literal, Suffix
double Literal
-1.0
1.
+3.32E-2
float Literal, Suffix F
-1.0f
1.F
+3.32e-2f
long double Literal, Suffix L
-1.0L
1.L
+3.32E-2L

Zeichen- und String-Literale

Zeichen-Literale sind einzelne Buchstaben oder Escape-Sequenzen, die in Hochkomma eingeschlossen sind. Sie besitzen den Datentyp char. Um ein Zeichen-Literal mit einem davon abweichenden Datentyp zu definieren, ist dem Zeichen ein Präfix laut nachfolgender Tabelle voranzustellen.

Literal, Präfix
Zeichen
String
char
'a'
"ein String"
char8_t, Präfix u8
u8'a'
u8"ein String"
char16_t, Präfix u
u'a'
u"ein String"
char32_t, Präfix U
U'a'
U"ein String"
wchar_t, Präfix L
L'a'
L"ein String"

String-Literale werden in Anführungszeichen eingeschlossen und die Zeichen innerhalb des String-Literals sind defaultmäßig vom Datentyp char. Und auch hier gilt: Um ein String-Literal mit einem davon abweichenden Datentyp zu definieren, wird dem String ein Präfix vorangestellt.

Des Weiteren weisen String-Literale folgende Besonderheiten auf:

  • Der Datentyp der Strings ist "<Datentyp>-Feld mit n konstanten Zeichen", wobei n der Anzahl der Zeichen plus 1 ist.
  • Das Verändern von Zeichen in String-Literalen führt zu undefiniertem Verhalten!
  • Sie haben die Speicherklasse static.
  • Das letzte Zeichen eines String-Literals ist immer eine 0 (Null), daher die plus 1 bei der Anzahl der Zeichen in einem String.

Direkt hintereinanderstehende String-Literale werden stets zusammengefasst. Das Einzige worauf dabei zu achten ist, ist, dass keine String-Literale mit unterschiedlichen Datentypen hintereinanderstehen.

std::cout << "Dies ist EIN String- "     // String-Literal
             "Literal obwohl es über "   // ueber
             "mehrere Zeilen geht!\n";   // 3 Zeilen

Eine Abwandlung des String-Literals ist der Raw-String. Er hebt unter anderem die Sonderstellung des Backslash-Zeichens innerhalb eines Strings auf. Ein Raw-String hat folgende allgemeine Definition:

[PRÄFIX]R"DEL(text)DEL"

Der optionale PRÄFIX gibt den Datentyp des Raw-Strings laut vorheriger Tabelle an. Danach folgen der Buchstabe R und ein Anführungszeichen. Unmittelbar nach dem Anführungszeichen folgt der Delimiter (Begrenzer) DEL, der aus einer beliebigen Anzahl von Zeichen bestehen kann, und anschließend, in einem Klammerpaar eingeschlossen, der eigentliche String. Nach der schließenden Klammer folgt nochmals der Delimiter DEL, der mit dem vor dem Text stehenden Delimiter übereinstimmen muss. Abgeschlossen wird der gesamte Ausdruck mit einem Anführungszeichen.

1: int main()
2: {
3:    auto rstring = R"#+(ein Text mit \n Escape Sequenz
4:       und Zeilenumbruch und Sonderzeichen # +)#+";
5:    std::cout << rstring << '\n';
6: }

ein Text mit \n Escape Sequenz
         und Zeilenumbruch und Sonderzeichen # +

Wie in der Ausgabe zu sehen ist, wird nicht nur die Sonderstellung des Backslash-Zeichens aufgehoben, sondern der String wird exakt so interpretiert, wie er in der Anweisung steht, einschließlich des Zeilenumbruchs. Der Delimiter im obigen Beispiel besteht aus der Zeichenfolge #+ und steht einmal vor der öffnenden Klammer und einmal nach der schließenden.

Benannte Konstanten

Benannte Konstanten werden prinzipiell wie initialisierte Variablen definiert, d.h., sie haben einen Datentyp, einen Namen und einen Initialisierungswert. Zusätzlich wird entweder vor dem Datentyp oder vor dem Namen des Datums das Schlüsselwort const gestellt.

1: int const NOOFLINES = 24;   // Init. per Zuweisung
2: const auto PI{3.1416f};     // Preventing narrowing
3: const char LINEFEED('\n');  // Initialisierung

Benannte Konstanten sind standardmäßig modulglobal, d.h., sie gelten nur in der Quellcode-Datei, in der sie definiert sind. Wird eine benannte Konstante in mehreren Modulen benötigt, sollte die Konstante in einer Header-Datei (.h Datei) definiert werden, die dann in den Quellcode-Dateien mittels #include "xx.h"; eingebunden wird. Im nachfolgenden Beispiel wird die Konstante PI in der Header-Datei myinc.h definiert. Diese Datei wird dann sowohl in der Quellcode-Datei main.cpp als auch in der Quellcode-Datei mod1.cpp eingebunden. Dadurch ist in beiden Quellcode-Dateien die Konstante bekannt.

1: // Datei myinc.h
2: const auto PI{3.1416f};
1: // Datei main.cpp
2: #include <iostream>
3: #include <print>
4: #include "myinc.h"
5:
6: int main ()
7: {
8:    std::println("Pi hat den Wert {}", PI);
9: }
1: // Datei mod1.cpp
2: #include <iostream>
3: #include <print>
4: #include "myinc.h"
5:
6: void PrintIt ()
7: {
8:    std::println("Pi hat den Wert {}", PI);
9: }

Für häufig benötigte numerische Konstanten, wie z.B. PI, enthält die Header-Datei <numbers> vordefinierte Konstanten, die im Sub-Namensraum numbers liegen.

1: #include <print>
2: #include <numbers>
3: int main()
4: {
5:    std::println("{}",std::numbers::pi);
6: }

Eine Übersicht über die vordefinierten Konstanten finden Sie u.a. auf https://www.cppreference.com unter dem Stichwort 'Mathematical constants'.

constexpr Spezifizierer

Der Spezifizierer constexpr weist den Compiler an, einen Ausdruck zum Zeitpunkt des Übersetzungsvorgangs auszuwerten. Kann der Ausdruck während des Übersetzungsvorgangs nicht berechnet werden, erzeugt dies einen Fehler. Und auch dazu ein Beispiel:

1: int main(int argn, char** argv)
2: {
3:    const auto var1 = argn+10;       // ok
4:    constexpr auto var2 = argn+20;   // Fehler!
5:    constexpr auto var3 = 10;        // ok
6: }

Das Beispiel zeigt den generellen Unterschied zwischen einer mit const definierten Konstanten und einer constexpr. Während const dem Compiler nur mitteilt, dass die Konstante nach ihrer Definition nicht mehr verändert wird, muss der Wert einer constexpr zum Übersetzungszeitpunkt bekannt sein. So führt die Definition von var2 zu einem Übersetzungsfehler, da der Ausdruck während des Übersetzungsvorgangs nicht berechnet werden kann. Welchen Wert var2 annimmt, hängt vom jeweiligen Inhalt des Parameters argn ab.


Copyright 2024 © Wolfgang Schröder
E-Mail mit Fragen oder Kommentaren zu dieser Website an: info@cpp-tutor.de
Impressum & Datenschutz