C++ Tutorial

Typkonvertierungen

Mithilfe der Typkonvertierung wird der Datentyp eines Ausdrucks in einen anderen Datentyp konvertiert.

Folgende Typkonvertierungen stehen zur Verfügung:

const_cast<DTYP>(AUSDRUCK)
static_cast<DTYP>(AUSDRUCK)
dynamic_cast<DTYP>(AUSDRUCK)
reinterpret_cast<DTYP>(AUSDRUCK)

DTYP ist der Datentyp, in den AUSDRUCK konvertiert werden soll. Ob die Konvertierung zulässig ist oder nicht wird zur Compilezeit oder zur Laufzeit überprüft.

const_cast() Konvertierung

Die const_cast() Konvertierung entfernt oder fügt den const oder volatile Modifizierer zu einem Datentyp hinzu (volatile wird später erklärt). Dabei darf sich der neue Datentyp vom Ursprungsdatentyp nur durch den Spezifizierer const oder volatile unterscheiden.

1: // Zeiger auf konstante Zeichen
2: auto pConst = "Text";
3: // Zeiger auf veränderbare Zeichen
4: char *pVar;
5: // Konvertierung const char* nach char*; Fehler!
6: pVar = pConst;
7: // Aber so geht's
8: pVar = const_cast<char*>(pConst);
9: // Alternativ:
10: pVar = const_cast<decltype(pVar)>(pConst);

static_cast() Konvertierung

Die static_cast() Konvertierung wird eingesetzt, um zwischen Integer-Datentypen und Gleitkomma-Datentypen zu konvertieren. Ebenfalls eingesetzt wird der static_cast() Operator, um einen void-Zeiger in einen beliebigen anderen Zeiger (typisierten Zeiger) zu konvertieren.

1: // Konvertierung von long nach char
2: // Es wird nur das niederwertigste Byte uebernommen
3: long longVar = ..;
4: char charVar = static_cast<char>(longVar);
5:
6: // void-Zeiger in int-Zeiger konvertieren
7: void *pVal = ..;
8: int *pVar = static_cast<int*>(pVal);

Außerdem kann der static_cast() Operator ein Integer-Datum in einen enum-Wert konvertieren und umgekehrt. Der enum-Anweisung ist später ein eigenes Kapitel gewidmet.

Und zu guter Letzt kann der static_cast() Operator dazu verwendet werden, Objektzeiger zu konvertieren deren Klassen in einer Beziehung zueinander stehen (Stichwort: Ableitung). Diese Konvertierung wird im Kapitel Typkonvertierungen und Klassenzeiger behandelt.

reinterpret_cast() Konvertierung

Typkonvertierungen mittels reinterpret_cast() sind die fehlerträchtigsten, da sie in der Regel plattformabhängige Konvertierungen durchführen. Die reinterpret_cast() Konvertierung wird zum einen für die Konvertierung zwischen verschiedenen Zeigertypen und zum anderen für die Konvertierung von Integer-Daten in Zeiger und umgekehrt eingesetzt.

1: // Definitionen
2: char *pText = "Text";
3: void *pAny;
4: const unsigned long ADDR = 0x1230;
5: long lVal;
6:
7: // Konvertierungen Zeiger nach long
8: lVal = reinterpret_cast<long>(pText);
9: // Konvertierung nach char Zeiger
10: pText = reinterpret_cast<char*>(ADDR);
11: // Konvertierung zwischen Zeigern, jetzt mal mit decltype
12: pText = reinterpret_cast<decltype(pText)>(pAny);

dynamic_cast() Konvertierung

Die dynamic_cast() Konvertierung wird später im Anschluss an die Behandlung von abgeleiteten Klassen beschrieben, da sie nur in diesem Zusammenhang von Bedeutung ist (siehe Kapitel Typkonvertierungen und Klassenzeiger) Sie ist allein der Vollständigkeit wegen an dieser Stelle erwähnt.

Automatische Typkonvertierungen (Promotions)

Da alle Operationen nur Daten mit gleichen Datentypen verarbeiten, werden viele Konvertierungen durch den Compiler automatisch vorgenommen. Die Anpassung erfolgt in der Weise, dass der 'kleinere' Datentyp auf den 'größeren' erweitert wird. Ausnahme: Bei Zuweisungen wird der Datentyp des rechten Operanden immer an den Datentyp des linken Operanden angepasst.

Ohne auf alle Einzelheiten einzugehen, die im Standard mehrere Seiten füllen, gibt es folgende automatische Konvertierungen.

Integral Promotion

Daten vom Datentyp char, (un-)signed char und (un-)signed short können vom Compiler auf den Datentyp int erweitert werden, wenn dadurch der gesamte Wertebereich des Original-Datentyps abgedeckt wird. Ist dies nicht der Fall, wird eine Anpassung auf unsigned int versucht. Ebenfalls können enum und wchar_t Datentypen nach int bzw. long (sowohl signed als auch unsigned) umgewandelt werden. Und zum Schluss kann ein bool-Datum in einen int-Wert konvertiert werden, wobei für true gleich 1 und für false gleich 0 verwendet wird.

1: char var = 0x55;
2: if (var == 0x80)     // Konvertierung von char auf int!
3:
4: bool bVar = true;
5: int nVar = bVar;     // Konvertierung von bool auf int

Arithmetische Operatoren und Shift-Operatoren führen ihre Operation immer mindestens mit dem Datentyp int aus.

1: signed char a=100, b=3, c=2;
2: signed char res = a * b / c;    // Ergebnis ist res=150

Die Berechnung erfolgt hier von links nach rechts, d.h., es wird zuerst a*b berechnet und das Ergebnis daraus durch c geteilt. Würde die Berechnung als signed char Berechnung durchgeführt werden, würde a*b das Ergebnis 44 liefern (0x64*0x03=0x12c, als char Ergebnis 0x2c). Und dies geteilt durch 2 würde dann dezimal 22 ergeben. Tatsächlich liefert die Auswertung des Ausdrucks das erwartet Ergebnis von 150, da die Operanden vor der Operation auf int konvertiert werden.

Floating Promotion

Ein Datum vom Typ float wird bei Bedarf auf ein Datum vom Datentyp double konvertiert.

Floating-Integral Konvertierung

Ein Gleitkomma-Datum kann in ein Integer-Datum konvertiert werden, wobei die Nachkommastellen abgeschnitten werden.

Zeiger Konvertierungen

Ein Zeiger eines beliebigen Datentyps kann immer in einen void-Zeiger (typloser Zeiger) konvertiert werden. Des Weiteren kann ein Zeiger auf eine abgeleitete Klasse in einen Zeiger auf seine Basisklasse konvertiert werden. Dieser Sachverhalt spielt später eine wichtige Rolle.

Integral Konvertierung mit Rundungen

Obwohl keine Konvertierung im bisherigen Sinn, es thematisch aber hierher passt, stehen zwei Bibliotheksfunktionen für die Konvertierung von Gleitkommawerte in long- oder long long-Werte mit Rundung zur Verfügung.

constexpr long lround(FTYPE fval);
constexpr long long llround(FTYPE fval);

FTYPE ist dabei einer der Gleitkomma-Datentypen. Werden diese Funktionen eingesetzt, ist die Header-Datei <cmath> einzubinden.

1: #include <print>
2: #include <cmath>
3:
4: // main() Funktion
5: int main ()
6: {
7:     // 4 Gleitkommakonstanten definieren
8:     const double val1 = 1./3.;
9:     const double val2 = 2./3.;
10:    const float val3 = -1.F/3.F;
11:    const long double val4 = -2.L/3.L;
12:    // 4 Variablen mit den gerundeten Ergebnissen
13:    // der Gleitkomma-Konvertierungen definieren
14:    auto ierg1 = std::lround(val1);
15:    auto lerg = std::lround(val2);
16:    auto llerg = std::llround(val3);
17:    auto ierg2 = std::llround(val4);
18:    // Ausgabe der gerundeten Variablen
19:    std::println("lround({:.4}): {}",val1,ierg1);
20:    std::println("lround({:.4}): {}",val2,lerg);
21:    std::println("llround({:.4}): {}",val3,llerg);
22:    std::println("llround({:.4}): {}",val4,ierg2);>
23: }

lround(0.3333): 0
lround(0.6667): 1
llround(-0.3333): 0
llround(-0.6667): -1


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