3 Stimmen

Größe einer Struktur mit Unionen und Bitfeldern

Ich versuche, die Größe dieses Structs in Bytes zu zählen und habe ein paar Fragen

struct stc {
    int a;
    int b;
    char c;
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
    char arr[10];
    int z:2;
};

Ich überprüfe die Größe auf diese Weise:

int main(void) {
    printf("%zu\n", sizeof(struct stc));
}

und kompiliere mit:

gcc -std=c99 -m32 -Wall -Wextra test.c

Es ist gcc 4.9 und ich benutze einen 64-Bit-Computer, aber ich möchte zuerst mit 32-Bit-Werten versuchen, so -m32. Jetzt ist das Ergebnis 20, aber ich habe keine Ahnung warum. So zähle ich:

struct stc {     
    int a;        // +4 = 4
    int b;        // +4 = 8
    char c;       // +1 aber danach long, also +4 (Alignment) = 12
    union stc2 {
        long a0;  // +4 = 16
        int a1;
        int a2;
    };
    char arr[10]; // +8 (für arr[8]) und 2 Bits übrig = 24 (oder 28)
    int z:2;      // +4 = 28 (oder 32) 
                  // Ich bin mir nicht sicher, wie es mit den 2 Bits vom Char-Array
                  // und 2 Bits vom Int funktionieren wird, daher zähle ich 2 verschiedene Werte. 
};

Das war seltsam, also habe ich versucht, das herauszufinden und ich weiß, dass diese Union anscheinend die Größe 0 hat.

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };

sizeof(struct stc) == 0. Ich denke, das liegt an Compiler-Optimierung? Wenn ja, wie schaltet man sie aus? Wenn nicht, warum ist das so? Eine weitere Frage ist natürlich, wie man die Größe dieses Structs richtig zählt (mit oder ohne Optimierung) und warum die Größe dieses einfachen Structs:

struct stc {
    char arr[10];
};

10 beträgt und nicht 12. Ich dachte, dass jeder Wert auf 4, 8, 12, 16, 20 usw. ausgerichtet ist, wenn man dem Compiler nicht sagt, Werte nicht auszurichten.

5voto

Bill Lynch Punkte 76551

So you have a lot of questions in here. I'll answer some as I go:

Größe von struct beträgt Null?

Du hast den Code gegeben:

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
};

Beachte, dass du keine Variablen innerhalb des structs deklariert hast. Du hast wahrscheinlich gemeint, folgendes zu tun, was wahrscheinlich die gleiche Größe wie sizeof(long) haben wird.

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    } x;
};

Platzierung von Bitfeldern

Lass uns also versuchen herauszufinden, wo 20 herkommt. Zuerst schreiben wir den Typ ohne das union, das nichts macht (siehe vorherige Überschrift) neu.

Außerdem ist zu beachten, dass structs mit Bitfeldern nicht erforderlich sind, im Speicher genauso angeordnet zu werden wie normale Typen. Aber lass uns trotzdem einige Vermutungen anstellen.

struct stc {
    int a;        // Offset 0,  Größe 4
    int b;        // Offset 4,  Größe 4
    char c;       // Offset 8,  Größe 1
    char arr[10]; // Offset 9,  Größe 10
    int z:2;      // Offset 19, Größe 1
};

Also scheint es gut zu passen.

Wurde die Größe nicht auf 12 aufgerundet?

struct stc {
    char arr[10];
};

Also, jeder Typ hat eine Größe und eine Ausrichtungsanforderung. Für char sind beide normalerweise 1. Für uint32_t sind sie normalerweise beide 4. Aber je nach Architektur könnte die Ausrichtung unterschiedlich sein.

Also in diesem Fall ist der maximale Ausrichtungsbedarf jedes Elements des structs stc 1. Daher sind die Ausrichtungsanforderungen des gesamten structs immer noch 1, obwohl die Größe 10 beträgt.

Im Allgemeinen solltest du jegliches Padding hinzufügen, das nötig ist, damit die Deklaration struct stc x[2] bewirken würde, dass alle Elemente richtig ausgerichtet sind.

Empfehlungen

Es gibt also einige Dinge, die du hier tun kannst, um zu lernen, was dein Compiler macht.

  1. Wenn du Fragen zur Speicherplatzierung auf Stack Overflow postest, ist es sehr hilfreich, die in stdint.h definierten Typen zu verwenden. Diese enthalten Typen wie int32_t und int16_t. Diese sind nützlicher, weil es keine Verwirrung darüber gibt, welche Größe ein long hat.

  2. Du kannst das offsetof-Tool verwenden, um herauszufinden, wo ein Compiler die Members platziert. Du kannst etwas mehr darüber lernen, wie man es benutzt hier.

Es kann jedoch zu Padding kommen:

Hier ist ein ziemlich einfaches Beispiel für ein struct mit einer beträchtlichen Menge Padding, das der Compiler einfügen müsste.

struct x {
    uint64_t x; // Offset 0,  Größe 8
    char     y; // Offset 8,  Größe 1
                // Offset 9,  Größe 1 (Padding)
    uint16_t z; // Offset 10, Größe 2
                // Offset 12, Größe 4 (Padding)
};

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