====== Unions ====== Unions gleichen im Aufbau zunächst [[struct|Strukturen]]. Im Gegensatz zu [[struct|Strukturen]], werden die Daten jedoch nicht hintereinander abgelegt, sondern alle auf die gleiche Stelle gelegt. Das bedeutet, dass ein Datensatz, den anderen überschreibt! Das mag im ersten Moment sinnfrei klingen, es gibt jedoch sinnvolle Anwendungen für Unions. ===== Definition ===== Ein Union wird genau wie eine [[struct|Struktur]] aufgebaut, lediglich wird statt ''struct'' das Schlüsselwort ''union'' verwendet: union BeispielUnion { Datentyp Variable; Datentyp2 Variable2; ... }; ===== Verwendung ===== Eine Union kann beliebig viele Elemente besitzen, dazu gehören auch wieder Unions oder auch Strukturen. Fragt man mit [[c:sizeof]] die Größe der Union ab, so ist sie immer genau so groß, wie das größte Element in ihr. Auch der Zugriff auf ein Union entspricht dem Umgang mit Strukturen: union BeispielUnion test; test.Variable = 7; Datentyp2 temp = test.Variable2; ==== Konvertierungen ==== Als Beispiel: Möchte man sich das Bitmuster einer [[double|Double]]-Variable ansehen, so kann man sie nicht einfach in eine [[int|Integer]]-Variable casten, da eine [[double|Double]]-Variable doppelt so groß ist, wie eine [[int|Integer]]-Variable. Man müsste sie gewissermaßen auf zwei [[int|Integer]] casten können. Und das geht mit union: union DoubleConverter { double DoubleValue; unsigned int IntArray[2]; char CharArray[10]; }; Nun kann man eine beliebige Double-Variable im Union speichern. Da das IntArray an genau der gleichen Stelle im Speicher beginnt, lässt sich nun der Double-Wert, welcher 8 Byte im Speicher belegt, über die zwei Integer-Werte, welche jeweils 4 Byte an der gleichen Stelle im Speicher belegen abrufen. Das [[Char]]-Array ist sogar noch etwas größer. Hier kann man die Werte Byte-Weise abrufen und sogar noch zwei weitere Chars speichern. Das Union ist damit 10 Byte groß, denn das größte Element, das Char-Array, ist 10 Byte groß. int main( void ) { union DoubleConverter dc; dc.DoubleValue = 123.0; printf( "Hexadezimaldarstellung: %x | %x\n", dc.IntArray[0], dc.IntArray[1] ); }; ==== Datenhaltung unterschiedlicher Daten ==== Benötigt man eine Datenstruktur, die abstrakte Gemeinsamkeiten, aber dafür unterschiedliche Daten verwenden, so lässt sich dies ebenfalls über Unions regeln. Nehmen wir als Beispiel ein grafisches Objekt, das entweder ein Kreis, eine Linie oder ein Rechteck sein soll: #define GO_TYPE_CIRCLE 1 #define GO_TYPE_LINE 2 #define GO_TYPE_RECT 3 struct GraficObject { /* Gemeinsam genutzte Daten */ int type; int x, y; /* Bisher 3 int => 12 Bytes */ union { struct { int width; int height; } rectancle; // 8 Bytes struct { int destX; int destY; } line; // 8 Bytes struct { int radius; } circle; // 4 Bytes } data; }; Jede dieser Strukturen vom Typ GrafikObject ist genau 20 Byte groß. Der Datenbereich, der hier im Union 'data' beschrieben ist, wird je nach Typ unterschiedlich interpretiert, je nachdem ob man ihn als data.rectancle, data.line oder data.circle anspricht. In C++ würde man hier vermutlich Ableitungen bilden und die gemeinsam genutzten Daten in eine Oberklasse setzen. Damit wird eine Klasse 'Circle' sogar nur 16 Byte groß - man spart also sogar vier Byte. Da man nun aber nicht mehr weiß, wie groß ein GraficObject ist, kann man Linien, Rechtecke und Kreise nun nicht mehr in Arrays speichern. Überall, wo Daten serialisiert werden, zum Beispiel beim Speichern in eine Daten, verliert man die Garantie, dass das nachfolgende Grafikobjekt 20 Bytes später folgt. Unions haben damit auch in Zeiten von Objektorientierung durchaus noch ihre Existenzberechtigung, wenn es darum geht, den Zugriff auf Strukturen zu optimieren. ---- [[http://forum.proggen.org/viewtopic.php?f=39&t=908&start=0|Autorendiskussion]]