Ich bin kürzlich auf diese Präprozessordirektive #pragma pack(1) gestoßen und habe mich gefragt, warum sie verwendet wird.
Ich habe die Verwendung gegoogelt und festgestellt, dass es andere Optionen wie Push, Pop usw. gibt. Hat jemand dies in seiner eingebetteten Anwendung verwendet?
Ich würde gerne einige Beispiele dafür erfahren, wie/warum Sie diese Richtlinie verwendet haben und auf welche Art von Auftragsverarbeiter? Was sind die Vor- und Nachteile der Verwendung dieser Richtlinie?
Danke.
#pragma pack(1)
stellt sicher, dass C struct
-Elemente der Reihe nach und auf Byte-Grenzen gepackt werden. Es kann RAM sparen - was in einem Mikrocontroller oft wertvoll ist.
Gepackte Strukturen ermöglichen auch das Casting direkt über Speicherpuffer für den Datenaustausch:
void f(void *buf)
{
struct ip_header *hdr = (struct ip_header *)buf;
hdr->dst = 0x8000001;
}
Seien Sie vorsichtig, wo Sie verwenden #pragma pack
. Es hat einen globalen Bereich (wie es im Präprozessor ist), also wirkt sich das Vergessen, es auszuschalten, auf alle #include
Dateien aus. Wenn Sie nur bestimmte Strukturen packen möchten, sollten Sie die Verwendung von GCC in Betracht ziehen __attribute__ ((packed))
.
Aufgrund von Ausrichtungsproblemen können gepackte Strukturen jedoch die Leistung beeinträchtigen. Zum Beispiel:
Wenn in Bytes gepackt:
struct
{
uint8_t a;
uint32_t b;
uint8_t c;
uint8_t d:
};
Wird gespeichert als (ohne Berücksichtigung der Endianness):
a, b0, b1, b2, b3, c, d
Viele Architekturen erfordern jedoch, dass 32-Bit-Zugriffe auf 32-Bit-Adressen ausgerichtet werden. Mit der gepackten Struktur muss die Maschine mehrere Byte-Zugriffe durchführen und sie dann wieder zusammenfügen.
Konfrontiert mit dem oben struct
Gesagten ohne aktiviertes Packen, könnte der Compiler es reorganisieren als:
b0, b1, b2, b3, a, c, d
Ein weiterer Grund, Strukturen an Byte-Grenzen zu packen, besteht darin, die Ausrichtung der Mitglieder sicherzustellen, wenn Daten zwischen verschiedenen Prozessoren übertragen werden.
Ich muss häufig Datenstrukturen zwischen einer MCU und einer Host-PC-Anwendung übertragen. Der PC packt Strukturen auf 32-Bit-Grenzen, wenn er nicht angewiesen wird, sie auf 1-Byte-Grenzen zu packen. Eine PIC24F-MCU packt Strukturen auf 16-Bit-Grenzen, es sei denn, sie werden angewiesen, sie auf 1-Byte-Grenzen zu packen.
Indem beide angewiesen werden, ihre Strukturen auf 1-Byte-Grenzen zu packen, wird sichergestellt, dass sich die Daten beim Zugriff an beiden Enden an derselben Stelle befinden. Ohne sie müssten Sie die Strukturen mit Reservebytes auffüllen, damit die Datenmitglieder richtig ausgerichtet werden.
Die traditionelle Verwendung, bei der ich dies gesehen habe, ist das Lesen von Informationen aus Dateien. Beispielsweise können Sie eine Struktur definieren, deren Mitglieder mit denen eines BMP-Dateiheaders übereinstimmen, und dann den gesamten Header in einem schnellen Lesevorgang lesen. OK, BMP ist vielleicht nicht das beste Beispiel (sein Header hat keine Ausrichtungsprobleme auf 32-Bit-Systemen), aber Sie haben die Idee. Ich nehme an, dass dies in der eingebetteten Welt genauso nützlich ist.
WütendEE