C++ Kurs

Typkonvertierungen

Die Themen:

Einleitung
C++ Typkonvertierungen
Automatische Typkonvertierungen (Promotions)

Einleitung

Kommen wir nun zu einem recht heiklen Thema, der Typkonvertierung (Typumwandlung). Mittels Typkonvertierung kann der ursprüngliche Datentyp, z.B. einer Variable, einer Konstante oder eines Ausdrucks (im Folgenden Datum genannt), in einen anderen Datentyp konvertiert werden. Wie Sie in der Zwischenzeit bereits erfahren haben, wird bei Operationen mit ungleichen Datentypen, soweit wie möglich, eine automatische Typkonvertierung durch den Compiler vorgenommen, da Operatoren nur Daten mit gleichen Datentypen verarbeiten können. Wir werden uns in dieser Lektion ansehen, wie Sie explizit solche Typkonvertierungen durchführen und wie die automatische Typkonvertierung arbeitet.

Wie stand es irgendwo einmal geschrieben: Typkonvertierung ist etwas für Experten; da müssen Sie dem Compiler sagen was er tun soll! Und dieser Satz trifft genau ins Schwarze. Durch eine nicht genau durchdachte Typkonvertierung können Sie Ihr Programm relativ leicht zum Absturz bringen.

Typkonvertierung im alten Stil (C-Stil)

Fangen mit der 'alten' Form der Typkonvertierung an. Diese Form sollten Sie aber in Zukunft so gut wie nicht mehr benützen. Sie enthält keinerlei Sicherheitsabfragen (d.h. die Datentypen können beliebig umgewandelt werden) und wird hier nur der Vollständigkeit halber aufgeführt.

Der Datentyp eines Datums kann mit folgenden Anweisungen explizit in einen anderen Datentyp überführt werden:

(DTYP) datum
DTYP (datum)

DTYP ist der neue Datentyp, in den das datum konvertiert werden soll.

Bei der Konvertierung eines Gleitkommawertes in eine Ganzzahl werden die Nachkommastellen abgeschnitten, es erfolgt keine Rundung. Beachten Sie dies bitte bei Ihren Berechnungen.


// Ausgangszustand
short var1 = 10;
short var2 = 4;
double result1, result2;

// Berechnung: double(10) / double(4)
// = 10.0 / 4.0
// = 2.5

result1 = (double)var1 / (double)var2;
// Berechnung: double(10 / 4)
// = double(2)
// = 2.0

result2 = double(10 / 4); 

Oben sehen Sie ein Beispiel mit der 'alten' Typkonvertierung. Wie Sie dem Beispiel auch entnehmen können, ist es nicht immer gleichgültig, wann Sie ein Datum konvertieren. Im Beispiel liefert die Division von Ganzzahlen ebenfalls eine Ganzzahl, auch wenn Sie diese anschließend in eine Gleitkommazahl umwandeln.

C++ Typkonvertierungen

C++ kennt folgende (neuen) Typkonvertierungen, die Sie in Zukunft einsetzen sollten, wenn Sie schon Daten konvertieren müssen:

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

DTYP ist auch hier der neue Datentyp, in den der Ausdrucks ARG konvertiert werden soll. Jede dieser Typkonvertierung wird für ganz spezielle Konvertierungen eingesetzt.

const_cast Konvertierung

Der const_cast Operator dient dazu, den const oder volatile Modifizierer von einem Datentyp zu entfernen (volatile wird später noch erklärt). Dabei darf sich der neue Datentyp vom Ursprungsdatentyp nur durch den Modifizierer const oder volatile unterscheiden. Alle anderen Konvertierungen führen zu einem Fehler beim Übersetzen des Programms. Als Ergebnis liefert const_cast den auf DTYP konvertierten Ausdruck. Die erste Zuweisung im Beispiel liefert einen Fehler, da ein Zeiger auf einen konstanten Text nicht einem Zeiger auf einen veränderlichen Text direkt zugewiesen werden kann. Wie's trotzdem geht, ist in der darunter stehenden Anweisung dargestellt, hier wird der const-Modifizierer entfernt.


// Zeiger auf konstante Zeichen
const char *pConst = "Text";
// Zeiger auf veränderbare Zeichen
char *pVar
// Das schlägt fehl!
pVar = pConst;
// Aber so geht's
pVar = const_cast<char*>(pConst);

Wenn Sie von einem Datentyp das const-Attribut entfernen sollten Sie genau wissen was Sie tun! In der Regel führt das Entfernen des const-Attributs nicht automatisch dazu, dass Sie danach die ursprüngliche Konstante verändern können. Manche Compiler legen Konstanten im ROM (Read-Only Speicher, z.B. Flash oder EEPROM) ab. Und Schreibzugriffe auf einen solchen Speicher können bis zum Programmabsturz führen!

static_cast Konvertierung

Der static_cast Operator wird eingesetzt, um zwischen Ganzzahl-Datentypen und Gleitkomma-Datentypen zu konvertieren. Die erste Anweisung im Beispiel konvertiert ein long-Datum in ein char-Datum. Beachten Sie hierbei bitte, dass nur das niederwertigste Byte übernommen wird, der Rest wird verworfen. Ebenfalls eingesetzt wird der static_cast Operator um einen void-Zeiger (Zeiger ohne bestimmtem Datentyp) in einen beliebigen anderen Zeiger (Zeiger mit bestimmtem Datentyp) zu konvertieren. So konvertiert die letzte Anweisung des Beispiels den void-Zeiger pVal in den int-Zeiger pVar.


// Konvertierung von long nach char
long longVar = ..;
char charVar = static_cast<char>(longVar);

// void-Zeiger-Konvertierung
void *pVal = ..;
int *pVar = static_cast<int*>(pVal);

Außerdem kann der static_cast Operator noch eine Ganzzahl in einen enum-Wert konvertieren. Allerdings müssen Sie dabei selber darauf achten, dass die zu konvertierende Ganzzahl innerhalb der in der enum-Anweisung definierten Konstanten liegt. Der enum-Datentyp werden später noch behandelt.

Der static_cast Operator kann auch dazu verwendet werden, Objektzeiger zu konvertieren deren Klassen in einer Beziehung zueinander stehen (Stichwort: Ableitung). Diese Konvertierung wird in der Lektion Typkonvertierungen auf Klassenzeiger später behandelt.

reinterpret_cast Konvertierung

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


// Definitionen
cchar *pText = "Text";
void *pAny;
const int CONST = 10;
llong lVal;

// Konvertierungen Zeiger nach long
lVal = reinterpret_cast<long>((pText);
// Konvertierung nach char-Zeiger
pText = reinterpret_cast<char*>(CONST);
/// Konvertierung zwischen Zeigern
pText = reinterpret_cast<char*>(pAny);

dynamic_cast Konvertierung

Der Konvertierungsoperator dynamic_cast wird später nach der Behandlung von abgeleiteten Klassen beschrieben, da er nur in diesem Zusammenhang von Bedeutung ist (sieh Lektion Typkonvertierungen auf Klassenzeiger) Er wird nur der Vollständigkeit wegen an dieser Stelle erwähnt.

AAutomatische Typkonvertierungen (Integral Promotions)

Viele 'alltägliche' Typanpassungen kann der Compiler automatisch vornehmen, wenn dadurch keine Information verloren geht. Beachten Sie bitte, dass vor dem Ausführen einer Operation (und auch eine Zuweisung ist eine Operation) immer die Datentypen der Operanden angepasst werden. Die Anpassung erfolgt in der Weise, dass der 'kleinere' Datentyp auf den 'größeren' erweitert wird.

Ohne jetzt auf alle Einzelheiten einzugehen, die im Standard ca. 8 DIN-A4 Seiten belegen, gibt es folgende wichtige Konvertierungen.

Integral Promotion

Werte vom Datentyp char,, unsigned char, signed char, unsigned short und signed short können vom Compiler auf den Datentyp int erweitert werden, wenn dadurch der gesamte Wertebereich des Originaldatentyps abgedeckt wird. Ist dies nicht der Fall, so wird eine Anpassung auf einen unsigned int Datentyp 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 Wert noch in einen int Wert konvertiert werden, wobei für true gleich 1 und für false gleich 0 verwendet wird.


cchar var = 0x55;
if (var == 0x80) // Konvertierung von var auf int!

bool bVar = true;
int nVar = bVar; // Konvertierung von bVar auf int

Floating Promotion

EEin Wert vom Typ float kann bei Bedarf auf einen Wert vom Datentyp double konvertiert werden.

Floating-Integral Konvertierung

Ein Gleitkommawert kann in einen Ganzzahlwert konvertiert werden, wobei die Nachkommastellen einfach abgeschnitten werden. Kann der Ganzzahlwert nicht exakt als Gleitkommawert dargestellt werden, so ist die entsprechende Rundung vom Compiler abhängig.

Zeiger Konvertierungen

Ein Zeiger eines beliebigen Datentyps kann immer in einen void--Zeiger (datentyp-loser Zeiger) konvertiert werden. Außerdem kann ein Zeiger auf eine abgeleitete Klasse stets in einen Zeiger auf die entsprechende Basisklasse konvertiert werden. Dieser Sachverhalt spielt später im Kurs noch eine wichtige Rolle.