Cast-Operationen und Konvertierung verschiedener Datentypen in ANSI C/C++

Letztes Update: Dienstag, 16. August 2016 - 16:41 Uhr

Auf dieser Seite findest du Beispiele für typische Fälle im Umgang mit unterschiedlichen Datentypen und einige Besonderheiten die es zu beachten gilt.
Dazu gibt es ein paar Infos zum Thema: Was passiert eigentlich "unter der Haube" bei Formatumwandlungen in ANSI C/C++?

Inhalt

1. Konvertierung Float -> Integer (explicit cast)

2. Reinterpretierung Float -> Integer (reinterpret cast)

3. Konvertierung Integer -> Float (explicit cast)



1. Konvertierung Float → Integer (explicit cast)

Zwei Variablen vom Typ float und int sind gegeben. Der int Variable soll der entsprechende Wert der float Variablen zugewiesen werden:

float  f = 1.0f;
int    i = 0;

// Explicit cast a float to integer
i = (float) f;

// Result: i == 1

Der folgende Disassembly Code zeigt das Beispiel nach der Compilerung:

004119BA  fld         dword ptr [f]
004119BD  call        @ILT+390(__ftol2_sse) (41118Bh)
004119C2  mov         dword ptr [i],eax 

Ergebnis:

  • Das Konvertieren von float nach int erfolgt durch Aufruf einer speziellen Funktion (__ftol2_sse), wenn vorhanden via SEE2.
  • Das Datenwort muss umgewandelt werden, der Code ist plattformunabhängig.
  • Der float Wert wird nicht gerundet, Nachkommastellen werden abgeschnitten.
  • Die Wertebereiche von float und int sind sehr unterschiedlich, so dass es zu Ungenauigkeiten kommen kann!

Beispiel für ein Genauigkeitsproblem:

f = 1e10;        // The number is too large for a 32-bit integer
i = (int)   f;
f = (float) i;

// Result: f == -2.1474836e+009
//         i == -2147483648

 

2. Reinterpretierung Float → Integer (reinterpret cast)

Zwei Variablen vom Typ float und int sind gegeben. Der int Variable soll der Wert aus dem Speicherplatz der float Variablen zugewiesen werden:

float  f = 1.0f;
int    i = 0;

// Reinterpret float as integer via pointer
i = *((int*) &f);

// Result: i == 0x3f800000 (Plattform mit 32-bit float und 32-bit integer)

Der folgende Disassembly Code zeigt das Beispiel nach der Compilerung:

// Compiled Result (disassembly):
004119C5  mov         eax,dword ptr [f] 
004119C8  mov         dword ptr [i],eax 

Ergebnis:

  • Nur wenige und sehr simple Assembler-Anweisungen benötigt.
  • Simples Kopieren eines Wortes ohne Konvertierung des Datentyps, sehr schnelle Operation.
  • Code ist plattformabhängig und der int Wert entspricht nicht dem float Wert.

Andere Möglichkeit mittels Union:

// Reinterpret float as integer via union
union 
{
  float f;
  int   i;
} u;
  
u.f = f;
i   = u.i; 

Disassembly:

0041723B  fld         dword ptr [f] 
0041723E  fstp        dword ptr [u]  
00417241  mov         eax,dword ptr [u] 
00417244  mov         dword ptr [i],eax
  • Vorteil: Bessere Lesbarkeit
  • Union erlaubt den Zugriff auf einen Speicherbereich über unterschiedliche Typen

 


3. Konvertierung Integer → Float (explicit cast)

Zwei Variablen vom Typ float und int sind gegeben. Der float Variable soll der entsprechende Wert der int Variablen zugewiesen werden:
float  f = 0.0f;
int    i = 1;

f = (float) i;

// Result: f == 1.0f

Ergebnis:

  • Der Wertebereich ist nicht identisch: Die float Zahl hat typischerweise nur 24-Bit für die Mantisse, durch die Konvertierung kann Genauigkeit verloren gehen.
  • Daher geben viele Compiler an dieser Stelle eine Warnung aus!

Beispiel für ein Genauigkeitsproblem:

float  f = 0.0f;
int    i = 111111111111;    // = 0x423a35c7 (the number is too large for a 24-bit float mantissa)

f = (float) i;
i = (int) f;

// Result: f == 1.1111112e+009
//         i == 1111111168  // = 0x423a3600

 

Hast du Anmerkungen zu den gezeigten C/C++ Codes, weitere hilfreiche Tipps oder Hinweise? Ich würde mich über Feedback freuen...

 

Neuen Kommentar abgeben

dk2yx