17.9 Union
 
Eine weitere Möglichkeit, Daten zu strukturieren, sind Unions (auch Varianten genannt). Abgesehen von einem anderen Schlüsselwort, bestehen zwischen Unions und Strukturen keine syntaktischen Unterschiede. Der Unterschied liegt in der Art und Weise, wie mit dem Speicherplatz der Daten umgegangen wird. Hierzu ein Beispiel der Speicherplatzbelegung einer Struktur:
struct test1 {
char a;
int b;
double c;
};
 Hier klicken, um das Bild zu Vergrößern
Abbildung 17.8
Speicherbelegung bei einer Struktur
Diese Struktur benötigt 16 Byte an Speicher. Das gleiche Beispiel jetzt mit dem Schlüsselwort union:
union test2 {
char a;
int b;
double c;
};
Intern sieht dies mit union folgendermaßen aus:
 Hier klicken, um das Bild zu Vergrößern
Abbildung 17.9
Speicherbelegung einer Struktur mit dem Schlüsselwort union
Hierzu ein Listing, welches den Unterschied demonstrieren soll:
/* union1.c */
#include <stdio.h>
#include <stdlib.h>
struct test1 {
char a;
int b;
double c;
};
union test2 {
char a;
int b;
double c;
};
int main(void) {
printf("struct benoetigt %d Bytes\n", sizeof(struct test1));
printf("Union benoetigt %d Bytes\n", sizeof(union test2));
return EXIT_SUCCESS;
}
Die Struktur mit dem Schlüsselwort union besitzt jetzt nur noch acht Bytes?! Dies verursacht das Schlüsselwort union und das größte Element in der Struktur, double. Dieser ersparte Speicherplatz wird allerdings mit dem Nachteil erkauft, dass immer nur ein Element in dieser Struktur verwendet werden kann. Beispielsweise wird dem Strukturelement int b der Wert 100 übergeben:
text.b = 100;
Somit beträgt die Speichergröße der Struktur trotzdem acht Bytes für einen Integer, da der größte Datentyp in der union nämlich double lautet. Übergeben Sie jetzt an double c den Wert 10.55:
text.c = 10.55;
Jetzt können Sie auf den Wert von int b nicht mehr zugreifen, da dieser von double c überlappt wurde. Zwar kann es immer noch sein, dass int b weiterhin den Wert 100 ausgibt, aber dies wäre Zufall, denn der Speicherbereich wurde überdeckt. Das Verhalten ist in diesem Fall undefiniert.
Welchen Vorteil hat es, wenn immer auf ein Element einer Struktur zugegriffen werden kann? Der wesentliche Vorteil liegt in der Anwendung von Union zum Einsparen von Speicherplatz bei der Verarbeitung großer Strukturen; beispielsweise bei Strukturen, wo bestimmte Elemente niemals miteinander auftreten. Ein Computerspiel z.B., bei dem sich immer einer gegen einen, Auge um Auge, duelliert. In dem folgenden Codeabschnitt wurde eine Struktur mit vier verschiedenen Gegnercharakteren erstellt:
struct gegner {
union {
struct {
char name[20];
int power;
unsigned char leben;
unsigned int geschwindigkeit;
} fighter1;
struct {
char name[20];
int power;
unsigned char leben;
unsigned int geschwindigkeit;
} fighter2;
struct {
char name[20];
int power;
unsigned char leben;
unsigned int geschwindigkeit;
} fighter3;
struct {
char name[20];
int power;
unsigned char leben;
unsigned int geschwindigkeit;
} fighter4;
};
} dat;
Damit wird immer nur auf eine Struktur zugegriffen, was in diesem Beispiel ausreichend ist, denn es sollten immer nur die Daten eines Gegners im Speicher sein, eben die, die im Augenblick nötig sind. So könnten Sie z.B. den fighter4 mit Werten initialisieren:
strcpy(dat.fighter4.name, "Superman");
dat.fighter4.power = 5;
dat.fighter4.leben = 1;
dat.fighter4.geschwindigkeit = NORMAL;
Der Zugriff auf die einzelnen Elemente erfolgt wie bei den normalen Strukturen.
Zurück zum Programm der Adressverwaltung, denn dieses eignet sich auch prima für eine Union:
struct adres {
union {
struct {
char vname[20];
char nname[20];
long PLZ;
char ort[20];
int geburtsjahr;
} privat;
struct {
char vname[20];
char nname[20];
long PLZ;
char ort[20];
char sternzeichen[20];
int geburtsjahr;
} geschaeftlich;
};
} adressen[100];
Hiermit können 100 Adressen gespeichert werden. Mithilfe dieser Union wird das Private vom Geschäftlichen getrennt.
Natürlich können Sie mit dem Schlüsselwort union auch ein Array von Unions realisieren. Der Zugriff und die Initialisierung erfolgen genauso wie bei den Strukturen bereits beschrieben. Ein Beispiel:
/* union2.c */
#include <stdio.h>
#include <stdlib.h>
union number {
float x;
int y;
};
int main(void) {
union number mixed[2];
mixed[0].x = 1.123;
mixed[1].y = 123;
mixed[2].x = 2.345;
printf("%.2f\t%d\t%.2f\n",
mixed[0].x, mixed[1].y, mixed[2].x);
return EXIT_SUCCESS;
}
Wenn Sie eine Union initialisieren, erlaubt ANSI C nur einen Initialisierer. Und standardmäßig bedeutet dies, dass immer das erste Element der Union initialisiert wird. Es gibt keine Standardlösung, um die anderen Elemente zu initialisieren. Ein Beispiel:
union 2_D {
int x;
int y;
};
// coordinate.x hat den Wert 123
union 2_D coordinate = { 123 };
Achtung Sollten Sie vorhaben, Ihre Programme auf andere Systemen zu portieren, so müssen sie sich hundertprozentig mit dem Alignment diverser Systeme auskennen, sofern Sie Unions einsetzen wollen. Ansonsten dürften Sie Probleme mit der Portierung bekommen.
|
|