Was sind speziell bei GCC (d. h. beim Kompilieren beider mit GCC) die Unterschiede zwischen der Funktionsweise der folgenden beiden?
struct foo1 {
char a;
int b;
} __attribute__((__packed__, aligned(n) ));
und:
#pragma pack(push, n)
struct foo2 {
char a;
int b;
};
#pragma pack(pop)
Sie scheinen sich anders zu verhalten:
foo1 f1;
foo2 f2;
int& i1 = f1.b; // ok
int& i2 = f2.b; // cannot bind packed field 'f2.foo2::b' to 'int&'
Warum ist bei dem einen ein Fehler und bei dem anderen nicht? Sind die Speicherlayouts zumindest gleich?
Sie sagen nicht, welche Version von GCC Sie verwenden, aber Sie können das entsprechende Handbuch finden online. In dieser Hinsicht sind sie jedoch alle ziemlich kompatibel, da das Verhalten von Attributen und Pragmas, sobald sie einmal definiert sind, normalerweise aus Kompatibilitätsgründen über Versionen hinweg beibehalten wird. Konkret zitiere ich aus dem Handbuch zu GCC 4.9.3, der derzeit neusten verfügbaren Version aus der GCC 4-Reihe. Insbesondere die Abschnitte auf Typattribute und weiter Strukturpackende Pragmas sind relevant.
Das GCC-Handbuch sagt von #pragma pack
und Freunde:
#pragma-Direktiven, die die ändern maximal Ausrichtung von Mitglieder von Strukturen (außer Bitfeldern mit Nullbreite), Vereinigungen und Klassen, die anschließend definiert werden.
(Betonung hinzugefügt). Es sagt von __attribute__((packed))
:
Dieses Attribut, das an eine Struktur- oder Vereinigungstypdefinition angehängt ist, gibt an, dass jedes Element (außer Bitfeldern mit Nullbreite) der Struktur oder Vereinigung platziert wird, um den erforderlichen Speicher zu minimieren.
Es sagt von __attribute__ ((aligned(n)))
:
Dieses Attribut gibt a an Minimum Ausrichtung für Variablen des angegebenen Typsgemessen in Byte.
(Betonung hinzugefügt).
Also nein, #pragma pack(n)
mit oder ohne push
bedeutet im Allgemeinen nicht dasselbe wie Anhängen __attribute__((packed, aligned(n))
zum Strukturtyp. Ersteres gibt an, dass Mitglieder betroffener Strukturen ausgerichtet werden n
-Byte oder feinere Grenzen. Letztere legt fest, dass Bauteile der betroffenen Struktur mit der minimal zulässigen Polsterung verpackt werden und dass die gewählte Ausrichtungsanforderung für Exemplare der Gesamtstruktur nicht geringer sein darf als n
. Diese sind nicht nur nicht gleich, sie sind sich nicht einmal sehr ähnlich.
Das solltest du finden #pragma pack(1)
Das Beeinflussen einer Strukturdefinition hat die gleiche Auswirkung auf das Layout von Instanzen wie das Anhängen __attribute__((packed))
zur Definition dieser Struktur. Selbst wenn sie das gleiche Ziel erreichen, sind sie es nicht gleiche Sache. Das Verhalten und die Auswirkungen beider liegen außerhalb der C++-Spezifikation, und GCC hat das Recht, sie in anderer Hinsicht anders zu behandeln.
Wenn Sie jedoch Attribute verwenden möchten, um die Ausrichtung von Strukturmitgliedern zu beeinflussen, müssen Sie zumindest einige Attribute mitgliedweise anwenden. Zum Beispiel …
struct foo1 {
char a;
int b __attribute__((aligned(n)));
} __attribute__((packed));
… könnte den gleichen Effekt haben wie …
#pragma pack(push, n)
struct foo2 {
char a;
int b;
};
#pragma pack(pop)
…, es hängt davon ab n
.