7 Stimmen

Ist es in C++ Standard, solche Strukturen auszurichten

Hier ein Beispiel

class A
{
public:
  int a; 
  char b;
  int c;
};

Jeder Compiler (für x86, 32 oder 64 Bit), den ich sehe, weist 12 Bytes für die Klasse A anstelle von 9. Sie richten sich also aus b zur Integer-Grenze oder Bus-Grenze kann man sagen. Meine Frage ist, ob dies in C++-Standard zu tun, und wenn es irgendwelche Compiler, die nicht wie das tun.

17voto

jalf Punkte 235501

Der C++-Standard legt dies fest:

  • Objekte haben eine Ausrichtungsanforderung, deren Größe ein Vielfaches davon ist (wenn also int 4 Bytes breit ist, ist eine Ausrichtung von 1, 2 oder 4 Bytes erforderlich, je nach Implementierung).
  • Mitgliedsobjekte (wenn sie nicht durch Zugriffsspezifikationen wie public ) werden alle in der Reihenfolge zugewiesen, in der sie deklariert werden
  • und sie werden unter Berücksichtigung ihrer Ausrichtungsanforderungen zugewiesen.

Die Norm besagt also nicht, dass die Klasse eine Größe von 12 Byte haben sollte.

Aber es fait sagen, dass b sollte zugewiesen werden nach a und dass c sollte zugewiesen werden nach b .

Auf einer Plattform, auf der int 4 Bytes breit ist und eine 4-Byte-Ausrichtung erfordert, bleiben 12 Bytes als kleinste gültige Größe übrig:

  • a nimmt die ersten 4 Bytes
  • b benötigt ein Byte
  • c benötigt 4 Bytes, sondern muss an einer 4-Byte-Grenze zugewiesen werden. b ein Byte beendet Vergangenheit eine solche Grenze, so dass die nächste gültige Position, an der c at wird durch Einfügen von 3 Bytes Füllmaterial gefunden.

Die Gesamtgröße der Klasse entspricht also der Größe der Mitglieder (4 + 1 + 4 = 9) plus drei Bytes Füllmaterial, also insgesamt 12.

Es gibt noch eine weitere Regel, die hier keine Auswirkung hat, die aber wichtig wäre, wenn Sie die Mitglieder in der Reihenfolge definiert hätten a, c, b stattdessen.

Die enthaltende Klasse ( A ) erbt die Ausrichtungsanforderung von dem am strengsten ausgerichteten Mitgliedsobjekt. Das heißt, weil es ein int hat es die gleichen Ausrichtungsanforderungen wie ein int tut. Und da die Gesamtgröße des Objekts ein Vielfaches der Ausrichtungsanforderung sein muss, muss eine Klasse, die die Mitglieder in der Reihenfolge a, b, c würde immer noch 12 Bytes Speicherplatz benötigen. Es würde einfach die 3 Bytes Füllung an das Ende der Klasse verschieben, anstatt zwischen b y c .

In einigen anderen Fällen kann die Neuordnung der Mitglieder in absteigender Reihenfolge der Größe jedoch manchmal die Größe einer Klasse zu reduzieren.

Nehmen wir an, wir hätten stattdessen eine Klasse wie diese:

class B {
  char a;
  double b;
  int c;
};

Dies hätte 24 Byte Speicherplatz erfordert (1 Byte für a , 8 Byte für b und 4 Bytes für c sondern auch, um sicherzustellen b auf einer 8-Byte-Grenze landet, bräuchten wir 7 Bytes zum Auffüllen zwischen a y b und um sicherzustellen, dass die gesamte Klasse am Ende ein Vielfaches von 8 ist, benötigen wir weitere 4 Bytes nach c .

Aber die Mitglieder werden nach ihrer Größe neu geordnet, etwa so:

class B {
  double b;
  int c;
  char a;
};

führt zu einer Klasse, die nur 16 Bytes benötigt:

die gleichen 1 + 4 + 8 Bytes für die Mitgliedsobjekte selbst, aber jetzt c bereits an einer 4-Byte-Grenze ausgerichtet ist (weil es nach b die an einer 8-Byte-Grenze endet) und a braucht nie eine Ausrichtung, so dass die einzige Ausrichtung, die wir brauchen, darin besteht, sicherzustellen, dass B hat eine Größe, die ein Vielfaches von 8 ist. Die Mitglieder benötigen 13 Bytes, also können wir 3 Bytes Füllung hinzufügen, und die Klasse ist am Ende 16 Bytes groß, 33% kleiner als die erste Version.

1voto

Anirudh Ramanathan Punkte 45125

Es ist möglich, das Packen von Strukturen zur Kompilierzeit mit Hilfe von Pragma-Direktiven zu steuern. Siehe #Pragma Pack

Im folgenden Beispiel werden die Mitglieder nicht ausgerichtet, sondern direkt nebeneinander platziert.

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

Beispiel aus aquí .

GCC unterstützt auch pragma pack. Die Richtlinie ist nicht Teil eines Standards, wird aber von vielen Compilern unterstützt.


Es sollte jedoch kein Grund bestehen, das oben genannte zu tun. Der Compiler richtet sie aus, um den Zugriff auf Mitglieder zu beschleunigen, und es sollte kein Grund, das zu ändern .

0voto

balki Punkte 24248

Der Standard erlaubt es den Compilern, bei Bedarf mehr Bytes einzufügen. Dies hängt im Wesentlichen von der Architektur des Hosts und nicht vom Compiler ab.

0voto

Gorpik Punkte 10610

Ja, die Ausrichtung wird überall in der Norm erwähnt, vor allem in Abschnitt 3.11 ( Ausrichtung ). Sie ist plattformabhängig, so dass jedes Programm, das von der tatsächlichen Größe eines Objekts abhängt, von Natur aus nicht portierbar ist.

0voto

Aki Suihkonen Punkte 17797

In Ihrem Fall ist "b" immer richtig ausgerichtet. Es ist gepolstert zum Ausrichten c in 32-Bit-Grenzen. Auch wenn es einen gewissen Spielraum für spezifische Implementierungen gibt, befolgen die meisten Compiler die Regel, 2- und 4-Byte-Variablen an 2- und 4-Byte-Grenzen auszurichten.

In 32-Bit-Systemen werden auch Doubles und Long-Ints (8 Byte) an 4-Byte-Grenzen ausgerichtet, in 64-Bit-Systemen dagegen an 8-Byte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X