#pragma pack

Hallo,
ich will wie in dem vorherigen Artikel eine Struct in eine Datei schreiben, allerdings soll sie schon binär sein, also man soll die Integers später nicht lesen können.

Ich hab in einem Buch auch ein Bespiel mit fwrite gefunden, allerdings hat mich gewundert, das alle structs die in eine Datei geschrieben werden sollten so eine Kennung aufwiesen:

#pragma pack(push, 1)
Ich hab mal gegoogelt und herausgefunden, dass so eine Struct im RAM ausgerichtet wird und deshalb diese Beispielstruct nicht 9 Byte im Speicher belegt sondern 12! Mit diesen Pragma Direktiven wurde die Byte Zahl wieder auf 9 Byte reduziert. Benutzt man deshalb diese Direktiven, damit die Dateien, die gespeichert werden sollen nicht unnötig groß werden?

Ich hab auch unter Mircosoft geguckt, hab es aber nicht richtig verstanden, wo ist der Unterschied zwischen:


    
    #pragma pack(push, 1)
    struct x { int a; char b; int c; };
    #pragma pack(pop)



und 


    
    #pragma pack(1)
    struct x { int a; char b; int c; };



Vielen Dank für eine Antwort, viele Grüße 
Andreas

Hi Manfred!
#pragma pack ist eine Präprozessor Direktive, mit der man bestimmen kann wie Strukturen im Speicher ausgerichtet sein sollen. Normalerweise werden diese an Adresse gespeichert, die durch 4 Teilbar sind (je nach Prozessortyp). Ist ein Struct also kleiner, wird Platz verschwendet im Speicher, dafür ist die Zugriffszeit auf diese Daten kürzer.
#pragma pack stellt also das Alignment ein, wie die Daten im Speicher organisiert sind. Und zwar für den Rest der Datei, inklusive aller #include Dateien. Damit es keine Konflikte gibt, gibt es mit push und pop die Möglichkeit, die aktuellen Einstellung des Alignments auf einem Stack (Stapel) zu sichern (nur zur Compilezeit notwendig). Und wenn du deine Strukturen definiert hast, dann kannst Du die Originaleinstellung mit #pragma pop wieder hervorholen.
Dadurch wird verhindert, dass Du z.B. in einer Header Datei dass Alignment für deine Strukturen auf 1 setzt, und alle anderen diese Einstellungen ungewollt übernehmen müssen. Ausserdem kann Dir mit diesem Konstrukt egal sein, wie die aktuellen Alignment Settings an dieser Stelle der Quelldatei sind.

Grüsse,
Stefan

Hallo Andreas,

Grundsätzlich ist noch anzumerken, dass nur
#pragma
Teil der C-Spezifikationen ist, was dann dahinter steht ist Compiler spezifisch.
Hinzu kommt noch, dass Pragmas „als Empfehlung für den Compiler“ verstanden werden müssen. Grundsätzlich darf ein Compiler Pragma-Anweisungen auch ignorieren.

MfG Peter(TOO)

Mahlzeit!

Normalerweise werden diese an Adresse gespeichert, die
durch 4 Teilbar sind (je nach Prozessortyp).

In der Regel eher auf ein Alignment des Datentyps also char auf
Bytegrenze, short auf 2 Byte long auf 4 Byte und double…
letzterer hängt vom Compiler ab.

Ist ein Struct
also kleiner, wird Platz verschwendet im Speicher, dafür ist
die Zugriffszeit auf diese Daten kürzer.

Du hast zwar recht aber dies ist normalerweise nicht der Grund
sowas zu nutzen.

Heute würde ich behaupten der einzige Grund sowas zu nutzen ist
wenn das Programm mit der Außenwelt über diese Struktur kommunizieren
muß, sei es über Dateien, Netzwerk oder was auch immer.
Wenn verschieden Compiler, Rechner, Przessoren diese Struktur lesen
müssen, dann muß man halt vereinbaren wie die Bytes organisiert sind
und kann dies nicht dem Compiler überlassen.

Die Struktur des Orginalposters wird übrigens auf vielen Processoren
zu einer Exeption führen, daher kann/darf das eigentlich nichts sein
was auf die Welt losgelassen werden sollte (mißalignet Zugrif auf
int).

Wer sowas
-> struct x { int a; char b; int c; };
hinschreibt gehört geschlagen ob mit oder ohne pragma. :smile:

Gruß
Stefan

Hallo, vielen Dank für die vielen Antworten, ich denke ich habs jetzt verstanden :smile:

Wer sowas
-> struct x { int a; char b; int c; };
hinschreibt gehört geschlagen ob mit oder ohne pragma. :smile:

Das Beispiel hab ich von Mircosoft:
http://support.microsoft.com/kb/40027/de

Ich mein ist vielleicht dumm, da dann der letzte Integer nicht aligned ist, aber das so etwas zu einer Excpetion führt?

Viele Grüße

Andreas

Hallo Andreas,

-> struct x { int a; char b; int c; };

Ich mein ist vielleicht dumm, da dann der letzte Integer nicht
aligned ist, aber das so etwas zu einer Excpetion führt?

Manche CPUs können nur Wortzugriffe aufentsprechende Adressen ausführen.
Allerdings kann man bei einem passenden Compiler das Alignement gar nicht abschalten, bzw. zu kleine Werte einstellen.

MfG Peter(TOO)

Abend!

Ich mein ist vielleicht dumm, da dann der letzte Integer nicht
aligned ist, aber das so etwas zu einer Excpetion führt?

Die allermeisten Prozessorarchitekturen sind heute 32 Bit breit.
Auch wenn es ein wenig aufgeweicht wurde, heißt dies eigentlich
die CPU kann in einem Takt 32 Bit lesen und oder verarbeiten.
Dementsprechend sind die Speicher auch 32 Bit breit organisiert.
Sollte nun ein Prozessor die Aufgabe haben einen „int“ zu lesen
auf einer missaligned Adresse, dann muß die CPU zwei Lesezugriffe
machen und das resultierende „int“ aus den 64 Bit zusammenbasteln.

Außer Intel konnte sich niemand vorstellen das ein Programmierer
sowas dämliches hinschreibt. Dementsprechend können i86 Prozessoren
solche Zugriffe, ist zwar lahm aber geht. Alle anderen mir bekannten
Prozessoren laufen auf eine Exeption. Mit einem geeigneten Exeption-
Handler kann man das zwar lösen aber das macht kaum jemand, da der
Programmierer durchaus merken soll das er Bullshit macht.

Gruß
Stefan

Hallo Stefan,

Außer Intel konnte sich niemand vorstellen das ein
Programmierer sowas dämliches hinschreibt.

Das kommt daher, dass der 8086 eigentlich ein aufgebohrter 8080 war.

Auf der Linie 4004, 8008, 8080, 8086 wurde eigentlich immer nur erweitert (Schau dir nur mal die Registerarchitektur an).

Im Vergleich dazu haben ein 6800 und ein 68’000 nichts mehr gemeinsam.

Als der 8086 auf den Markt kam, gab es von Intel sogar ein Tool, mit dem man 8080-Assembler-Sourcen automatisch auf den 8086 portieren konnte. Das Ding hat sogar funktioniert.

MfG Peter(TOO)

Morgen Peter,

Das kommt daher, dass der 8086 eigentlich ein aufgebohrter
8080 war.

Soweit ich mich erinnere waren das doch 16 Bit Prozessoren bei denen
Intel damals auch schon den missaligned Zugriff (2 Byte von ungerader
Adresse lesen) zuließ.

Gruß
Stefan

Hallo Stefan,

Das kommt daher, dass der 8086 eigentlich ein aufgebohrter
8080 war.

Soweit ich mich erinnere waren das doch 16 Bit Prozessoren bei
denen
Intel damals auch schon den missaligned Zugriff (2 Byte von
ungerader
Adresse lesen) zuließ.

Der 8080 war noch ein 8-Biter, da stellte sich die Frage ja nicht.
Um dann möglichst kompatibel zu sein, hat man beim 8086 die selben Datenstrukturen wie beim 8080 zugelassen…
Ein 80286, 80386 und 80486 verhält sich nach einem Reset, um kompatibel zu bleiben, wie ein 8086 (maximal 1 MB Adressraum). Um in den nativen Mode zu kommen muss man dann per Software umschalten.

MfG Peter(TOO)

Hallo,
mal ein Extrembeispiel:

Wenn ich diese Strukt nehme und den zweiten Integer ausgeben lassen will und das Programm auf einem AMD Athlon ausführe müsste es einen Fehler geben? Aber es dürfte doch auch nur einen Fehler geben wenn ich die Ausrichtung mit #pragma pack(1) untersage, oder?

Viele Grüße
Andreas

Hallo Andreas,

mal ein Extrembeispiel:

Wenn ich diese Strukt nehme und den zweiten Integer ausgeben
lassen will und das Programm auf einem AMD Athlon ausführe
müsste es einen Fehler geben?

NEIN, der AMD Athlon kann ja alles, was ein Pentium auch kann.

Aber neben den PC-CPUs von Intel und AMD gibt es noch Hunderte andere CPU-Architekturen.

Aber es dürfte doch auch nur
einen Fehler geben wenn ich die Ausrichtung mit #pragma
pack(1) untersage, oder?

Allerdings ignoriert ein guter Compiler das Packen, bzw. gibt eine Warnung aus, wenn die CPU damit nicht umgehen kann.
Wenn man Programme schreibt, welche auf unterschiedlichen CPUs laufen sollen, muss man sich auch mit solchen Details auskennen.
Sowas kennt man, wenn man Programme z.B. für Unix/Linux schreibt.
Bei mir kommt das relativ häufig bei Protokoll-Treibern vor, welche auf einem PC und einem MicroController laufen sollen.
Weiterhin muss man noch beachten ob man eine CPU mit Little oder Big Endian hat. Mit der Erfahrung legt man dann aber seine Strukturen und Protokolle von Anfang an entsprechend an. Und das direkte binäre Einlesen von Strukturen lässt man dann auch sein.

MfG Peter(TOO)