Warum ist die sizeof
Operator für eine Struktur eine Größe zurück, die größer ist als die Gesamtgröße der Mitglieder der Struktur?
Antworten
Zu viele Anzeigen?Dies liegt an der Auffüllung, die hinzugefügt wurde, um die Ausrichtungsvorgaben zu erfüllen. Abgleich der Datenstruktur wirkt sich sowohl auf die Leistung als auch auf die Korrektheit von Programmen aus:
- Ein falsch ausgerichteter Zugriff kann ein schwerer Fehler sein (oft
SIGBUS
). - Ein falsch ausgerichteter Zugriff kann ein weicher Fehler sein.
- Entweder in der Hardware korrigiert, für eine bescheidene Leistungsverschlechterung.
- Oder durch Emulation in Software korrigiert werden, um eine starke Leistungsverschlechterung zu vermeiden.
- Darüber hinaus können Atomarität und andere Gleichzeitigkeitsgarantien gebrochen werden, was zu subtilen Fehlern führt.
Hier ist ein Beispiel mit typischen Einstellungen für einen x86-Prozessor (alle verwendeten 32- und 64-Bit-Modi):
struct X
{
short s; /* 2 bytes */
/* 2 padding bytes */
int i; /* 4 bytes */
char c; /* 1 byte */
/* 3 padding bytes */
};
struct Y
{
int i; /* 4 bytes */
char c; /* 1 byte */
/* 1 padding byte */
short s; /* 2 bytes */
};
struct Z
{
int i; /* 4 bytes */
short s; /* 2 bytes */
char c; /* 1 byte */
/* 1 padding byte */
};
const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */
Man kann die Größe von Strukturen minimieren, indem man die Mitglieder nach der Ausrichtung sortiert (bei Basistypen reicht die Sortierung nach der Größe aus) (z. B. Struktur Z
im obigen Beispiel).
WICHTIGER HINWEIS: Sowohl der C- als auch der C++-Standard besagen, dass die Strukturausrichtung implementierungsabhängig ist. Daher kann jeder Compiler die Daten anders ausrichten, was zu unterschiedlichen und inkompatiblen Datenlayouts führt. Aus diesem Grund ist es beim Umgang mit Bibliotheken, die von verschiedenen Compilern verwendet werden, wichtig zu verstehen, wie die Compiler die Daten ausrichten. Einige Compiler haben Kommandozeileneinstellungen und/oder spezielle #pragma
Anweisungen, um die Einstellungen für die Strukturausrichtung zu ändern.
Packen und Byte-Ausrichtung, wie in den C-FAQ beschrieben ici :
Es geht um die Ausrichtung. Viele Prozessoren können nicht auf 2- und 4-Byte Mengen (z.B. ints und long ints) zugreifen, wenn sie in alle Richtungen eingepfercht sind. in alle Richtungen.
Angenommen, Sie haben diese Struktur:
struct { char a[3]; short int b; long int c; char d[3]; };
N Struktur auf diese Weise in den Speicher zu packen:
+-------+-------+-------+-------+ | a | b | +-------+-------+-------+-------+ | b | c | +-------+-------+-------+-------+ | c | d | +-------+-------+-------+-------+
B es so anordnet:
+-------+-------+-------+ | a | +-------+-------+-------+ | b | +-------+-------+-------+-------+ | c | +-------+-------+-------+-------+ | d | +-------+-------+-------+
I Sie und ich sehen, wie sich die Felder b und c umdrehen? Kurz und bündig, es ist auch für den Prozessor schwierig. Daher polstern die meisten Compiler die Struktur (wie mit zusätzlichen, unsichtbaren Feldern) wie folgt auf:
+-------+-------+-------+-------+ | a | pad1 | +-------+-------+-------+-------+ | b | pad2 | +-------+-------+-------+-------+ | c | +-------+-------+-------+-------+ | d | pad3 | +-------+-------+-------+-------+
Wenn Sie wollen, dass die Struktur eine bestimmte Größe hat, verwenden Sie zum Beispiel mit GCC __attribute__((packed))
.
Unter Windows können Sie die Ausrichtung auf ein Byte setzen, wenn Sie das Programm cl.exe mit dem Befehl Option /Zp .
Normalerweise ist es für die CPU einfacher, auf Daten zuzugreifen, die ein Vielfaches von 4 (oder 8) sind, je nach Plattform und auch je nach Compiler.
Es ist also im Grunde eine Frage der Ausrichtung.
Sie müssen gute Gründe haben, sie zu ändern.
Dies kann auf die Ausrichtung der Bytes und das Auffüllen zurückzuführen sein, damit die Struktur auf Ihrer Plattform eine gerade Anzahl von Bytes (oder Wörtern) ergibt. Zum Beispiel in C auf Linux, die folgenden 3 Strukturen:
#include "stdio.h"
struct oneInt {
int x;
};
struct twoInts {
int x;
int y;
};
struct someBits {
int x:2;
int y:6;
};
int main (int argc, char** argv) {
printf("oneInt=%zu\n",sizeof(struct oneInt));
printf("twoInts=%zu\n",sizeof(struct twoInts));
printf("someBits=%zu\n",sizeof(struct someBits));
return 0;
}
haben Mitglieder, deren Größe (in Bytes) jeweils 4 Bytes (32 Bits), 8 Bytes (2x 32 Bits) und 1 Byte (2+6 Bits) beträgt. Das obige Programm (unter Linux mit gcc) gibt die Größen als 4, 8 und 4 aus - wobei die letzte Struktur so aufgefüllt wird, dass sie ein einzelnes Wort ist (4 x 8 Bit-Bytes auf meiner 32-Bit-Plattform).
oneInt=4
twoInts=8
someBits=4
Siehe auch:
für Microsoft Visual C:
http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx
und GCC behaupten Kompatibilität mit Microsofts Compiler..:
https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Structure_002dPacking-Pragmas.html
Zusätzlich zu den vorangegangenen Antworten, beachten Sie bitte, dass unabhängig von der Verpackung, in C++ gibt es keine "members-order-guarantee . Compiler können der Struktur Zeiger auf virtuelle Tabellen und Mitglieder von Basisstrukturen hinzufügen (und tun dies sicherlich auch). Selbst das Vorhandensein einer virtuellen Tabelle wird von der Norm nicht garantiert (die Implementierung des virtuellen Mechanismus ist nicht spezifiziert), so dass man zu dem Schluss kommen kann, dass eine solche Garantie einfach unmöglich ist.
Ich bin mir ziemlich sicher, dass Mitglied-Bestellung は garantiert in C aber ich würde mich nicht darauf verlassen, wenn ich ein plattform- oder kompilerübergreifendes Programm schreibe.
- See previous answers
- Weitere Antworten anzeigen
20 Stimmen
Siehe diese C-FAQ zur Speicherverwaltung. c-faq.com/struct/align.esr.html
71 Stimmen
Eine Anekdote: Es gab tatsächlich einen Computervirus, der seinen Code in Struktur-Paddings im Wirtsprogramm unterbrachte.
10 Stimmen
@Elazar Das ist beeindruckend! Ich hätte es nie für möglich gehalten, so winzige Flächen für irgendetwas zu nutzen. Können Sie weitere Einzelheiten nennen?
3 Stimmen
@Wilson - Ich bin sicher, dass es eine Menge jmp.
10 Stimmen
Siehe Struktur Polsterung, Verpackung : Die verlorene Kunst des Packens von C-Strukturen Eric S. Raymond
0 Stimmen
SO, answer
,Geeks4Geeks
, andere Verbindung0 Stimmen
Gibt es ein Padding zwischen 2 Structs, um das erste Mitglied des nächsten Structs an einer ausgerichteten Adresse beginnen zu lassen?
0 Stimmen
@Akshay Beide Strukturen beginnen ausgerichtet (es sei denn, Sie sorgen dafür, dass sie nicht ausgerichtet werden... byteweise Serialisierungen usw.)
0 Stimmen
Ich habe dieses Problem auch. Auch bei mir habe ich eine Struktur mit allen Bitfeldern, die zusammen 128 Bit ergeben. 128/8=16. Aber wenn ich sizeof aufrufe, erhalte ich 22 Bytes.
2 Stimmen
Es ist merkwürdig, dass fast 12 Jahre nach der Veröffentlichung und rund 195k Aufrufen niemandem aufgefallen ist, dass diese Frage ist eigentlich schlichtweg falsch .
2 Stimmen
@RobertSsupportsMonicaCellio es ist nur formal falsch. Buchstäblich gibt sizeof die Größe der Struktur zurück. Es ist nur so, dass die tatsächliche Größe größer ist als die Menge an Speicher, die ein Mensch, der die Deklaration betrachtet, wahrnimmt.