17.12 Attribute von Strukturen verändern (nicht ANSI C)
 
Der Speicherplatz für eine Struktur wird – wie schon bei den Arrays – lückenlos im Hauptspeicher abgelegt. Damit das System schneller auf diese Daten im Hauptspeicher zurückgreifen kann, werden diese in zwei oder in durch vier teilbare Adressen angeordnet. Dies ist abhängig vom Betriebssystem. Dabei wird einiges an Speicherplatz verschwendet. Zur Demonstration dient das folgende Programm:
/* alignment1.c */
#include <stdio.h>
#include <stdlib.h>
struct speicher {
char x;
int z;
};
int main(void) {
struct speicher test;
printf("%ld Bytes\n",sizeof(test));
return EXIT_SUCCESS;
}
Auf 32-Bit-Systemen dürfte diese Struktur acht Byte benötigen. Und dies, obwohl es eigentlich fünf Byte sein sollten (char + int = 5 Byte).
 Hier klicken, um das Bild zu Vergrößern
Abbildung 17.10
Speicherabbild mit einer Struktur mit unbenannten Lücken
Diese Abbildung stellt ein Vier-Byte-Alignment dar, wie es bei den meisten Systemen der Fall sein wird. Dabei entsteht eine Lücke von drei Byte (grau gefärbt), welche ungenutzt bleibt. Es wird hier auch vom »Padding« (Auffüllen, Polsterung) des Speichers gesprochen.
Hinweis Dies ist übrigens auch der Grund, warum Sie Strukturen nicht direkt miteinander vergleichen können. Auch ein Low-Level-Vergleich, Byte für Byte, kann da nicht viel helfen, da dieser durch zufällig gesetzte Bits in den Löchern verfälscht sein könnte. In solch einem Fall müssen Sie sich mit einer eigenen Funktion, welche die einzelnen Strukturelemente miteinander vergleicht, selbst behelfen.
|
Viele Compiler besitzen daher einen speziellen Schalter, mit dem diese Lücke entfernt werden kann. Wobei ich gleich anmerken muss, dass dies nicht ANSI C-konform und Compiler-abhängig ist.
Mit dem Schalter
__attribut__
können dem Compiler mehrere Informationen zu einer Funktion, zu Variablen oder Datentypen übergeben werden. Um damit eine lückenlose Speicherbelegung zu erreichen, könnten Sie das Attribut packed verwenden.
Sollte dieser Schalter bei Ihrem Compiler nicht funktionieren, können Sie auch das Pragma pack verwenden:
#pragma pack(n)
Für n kann hier der Wert 1, 2, 4, 8 oder 16 angegeben werden. Je nachdem, welche Angabe Sie dabei machen, wird jedes Strukturelement nach dem ersten kleineren Elementtyp oder auf n Byte abgespeichert.
Beim Testen auf verschiedenen Systemen und unterschiedlichen Compilern gab es keine Probleme mit dem #pragma pack. Die Option __attribut__ hingegen wurde nicht von jedem Compiler erkannt. Wie Sie dabei vorgehen, müssen Sie letztendlich selbst herausfinden.
Hier das Beispiel dazu:
/* alignment2.c */
#include <stdio.h>
#include <stdlib.h>
/* Lässt sich dieses Listing nicht übersetzen,
* entfernen Sie __attribute__((packed)) und
* verwenden stattdessen #pragma pack(1)
*/
/* #pragma pack(1) */
struct speicher {
char x;
int z;
} __attribute__ ((packed));
int main(void) {
struct speicher test;
printf("%ld Bytes\n",sizeof(test));
return EXIT_SUCCESS;
}
Damit benötigt die Struktur tatsächlich 5 Byte. Dies funktioniert bei manchen Compilern auch bei den enum-Aufzählungen:
/* alignment3.c */
#include <stdio.h>
#include <stdlib.h>
/* #pragma pack(1); */
enum{TRUE,FALSE}__attribute__ ((packed));
int main(void) {
printf("%ld Bytes\n",sizeof(TRUE));
return EXIT_SUCCESS;
}
Das Beispiel funktionierte beim Testen allerdings nur mit dem gcc-Compiler. In diesem Fall wird durch packed ein 1-Byte-Alignment angelegt. Das ist gegenüber den vier Bytes ohne packed beachtlich. Diese Werte können natürlich von System zu System unterschiedlich sein.
Hinweis Natürlich müssen Sie sich auch im Klaren sein, dass hier zwischen Performance und Speicherplatz entschieden wird. Schließlich greifen Sie ja in die geschwindigkeitsoptimierte Speicherung des Betriebssystems ein.
|
Bei den Vorteilen, die mit packed oder dem Pragma pack erzielt werden, sollten die Nachteile beachtet werden. Wenn diese Daten (struct speicher) auf einem System mit fünf Bytes pro Struktur in einer Datei gespeichert werden, kann es passieren, dass diese Daten auf einem anderen System falsch angezeigt werden, weil das System vielleicht dort die Option packed nicht kennt und einfach ignoriert. Außerdem könnten Low-Level-Funktionen fehlschlagen, da sich die Daten wegen des Alignments nicht dort befinden, wo die Funktionen diese vermutet.
|