12.2 Unions
Eine weitere Möglichkeit, Daten zu strukturieren, sind Unions (auch Varianten genannt). Ähnlich wie eine Struktur ist auch eine Union ein Verbund verschiedener Datentypen. Und ja: es heißt wirklich »eine Union« und nicht »ein Union«, weil es ja auch »eine Variante« heißt.
Abgesehen von den Schlüsselwörtern union und struct besteht auf den ersten Blick kein Unterschied zwischen Unions und Strukturen. Auch die Operationen und der Zugriff auf die Komponentenvariablen erfolgen wie bei den Strukturen.
Beim Speicherplatz allerdings gehen Strukturen und Unions aber doch auseinander. Bei Unions werden die einzelnen Komponenten nämlich nicht hintereinander im Speicher abgelegt, sondern alle Komponenten beginnen mit derselben Adresse. Somit kann immer nur auf die Variante zugegriffen werden, die als letztes im Speicher abgelegt wurde, denn eine Speicheradresse kann selbstverständlich nicht zwei Werte gleichzeitig aufnehmen. Aber was haben Sie für einen Vorteil davon, dass Sie nur immer eine Variante in einer Union verwenden können und darauf achten müssen, dass Sie die Komponente verwenden, in der Sie zuletzt etwas gespeichert haben? Die Antwort ist, dass Unions vor allem in den Anfangszeiten der Programmierung dazu verwendet wurden, Speicherplatz zu sparen, denn dieser war damals knapp. Deshalb wird in C auch externe Hardware oft noch mittels Unions angesprochen. Es folgt nun einfaches Beispiel, das Ihnen zeigt, wie Sie mit einer Union Speicherplatz sparen können:
00 // Kapitel12/union_beispiel.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 typedef struct rgb {
04 unsigned short red, green, blue;
05 } RGB;
06 typedef union color {
07 RGB rgb;
08 unsigned int hexRGB;
09 } Color;
10 int main(void) {
11 Color color01, color02;
12 color01.rgb.red = 127;
13 color01.rgb.green = 255;
14 color01.rgb.blue = 255;
15 color02.hexRGB = 0x7fffff;
16 printf("color01: %x%x%x\n",
color01.rgb.red,color01.rgb.green,color01.rgb.blue);
17 printf("color02: %x\n", color02.hexRGB);
18 return EXIT_SUCCESS;
19 }
In diesem Beispiel wird in den Zeilen (03) bis (05) zunächst ein Strukturtyp erstellt, in dem Farbwerte für Rot, Grün und Blau gespeichert werden können. In den Zeilen (06) bis (09) erstellen Sie eine Union mit einer Strukturvariablen vom eben erstellen Strukturtyp RGB und einer unsigned int-Variablen für den Farbwert als Hexadezimalzahl. In der Praxis können Sie jetzt nur einen der beiden Speicherbereiche der Union verwenden, also entweder rgb oder hexRGB.
Wenn Sie mit diesem Beispiel etwas experimentieren, werden Sie feststellen, dass es ohne Probleme möglich ist, Code zu kompilieren, der auf die anderen Komponenten einer Union zugreift bzw. den Zugriff versucht. Es findet hierbei aber keinerlei Überprüfung der Komponenten zur Übersetzungs- und Laufzeit statt. Wie bereits eingangs erwähnt, sind daher Sie als Programmierer dafür verantwortlich, dass auf die richtige Komponente aus der Union zugegriffen wird. Unions können deshalb eine fehlerträchtige Sache sein. In der Praxis werden Unions, außer in der Systemprogrammierung, oder wenn man komplexere Daten interpretieren will, eher selten verwendet.
Ein einfaches Praxisbeispiel könnte sein, dass ein direkter Zugriff auf die Hardware oder den Speicher notwendig ist. Das könnte wie folgt aussehen:
#include <stdint.h> // uint8_t, uint32_t
...
typedef union {
struct {
uint8_t byte_1;
uint8_t byte_2;
uint8_t byte_3;
uint8_t byte_4;
} bytes;
uint32_t dword;
} HardReg;
...
HardReg reg1, reg2;
reg1.dword = 0x2342341;
...
reg2.byte_2 = 2;
Ein weiteres gutes Beispiel könnte eine Schnittstelle sein, mit der Sie eine Verbindung über das Netzwerk, über den USB-Anschluss oder den internen Speicher herstellen wollen. Ein theoretischer Codeausschnitt hierzu wäre:
struct DataTransfer {
unsigned int securityKey;
unsigned char data[MAXSIZE];
union {
struct Network network;
struct USB usb;
struct Memory memory;
}
};
Größe einer Union
Es wird häufig irrtümlich angenommen, dass die Größe einer union der Größe der größten Komponente in einer union entspricht. Auch wenn das in der Praxis bei einem Beispiel einmal zutreffen sollte, ist diese Aussage im Allgemeinen falsch. Der Standard garantiert hier nur, dass die Größe einer union gleich sizeof(union type) ist.