Sök…


Introduktion

Som standard lägger C-kompilatorer upp strukturer så att varje medlem kan nås snabbt utan att påföra påföljder för "ojusterad åtkomst, ett problem med RISC-maskiner som DEC Alpha och vissa ARM-processorer.

Beroende på CPU-arkitekturen och kompilatorn kan en struktur ta mer plats i minnet än summan av storleken på dess komponentelement. Kompilatorn kan lägga till stoppning mellan elementen eller i slutet av strukturen, men inte i början.

Packning åsidosätter standardfyllningen.

Anmärkningar

Eric Raymond har en artikel om The Lost Art of C Structure Packing som är användbar att läsa.

Förpackningsstrukturer

Som standard är strukturer vadderade i C. Om du vill undvika detta beteende måste du uttryckligen begära det. Under GCC är det __attribute__((__packed__)) . Tänk på detta exempel på en 64-bitars maskin:

struct foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

Strukturen paddas automatiskt så att den har 8-byte inriktning och ser ut så här:

struct foo {
    char *p;     /* 8 bytes */
    char c;      /* 1 byte  */

    char pad[7]; /* 7 bytes added by compiler */

    long x;      /* 8 bytes */
};

sizeof(struct foo) kommer att ge oss 24 istället för 17 . Detta hände på grund av en 64-bitars kompilator läs / skriv från / till minne i 8 byte av ord i varje steg och uppenbart när du försöker skriva char c; en en byte i minnet, en fullständig 8 byte (dvs. ord) hämtas och konsumerar endast första byte av den och dess sju på varandra följande bitgrupper förblir tomma och inte tillgängliga för någon läs- och skrivoperation för strukturfyllning.

Strukturförpackning

Men om du lägger till attributet som är packed kommer kompilatorn inte att lägga till stoppning:

struct __attribute__((__packed__)) foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

Nu kommer sizeof(struct foo) att återvända 17 .

Generellt packade strukturer används:

  • För att spara utrymme.
  • Att formatera en datastruktur för att sända över nätverk utan att bero på varje arkitekturinriktning för varje nod i nätverket.

Det måste beaktas att vissa processorer som ARM Cortex-M0 inte tillåter ojusterad minnesåtkomst; i sådana fall kan strukturpaketering leda till odefinierat beteende och krascha CPU: n.

Struktur stoppning

Anta att denna struct definieras och kompileras med en 32-bitars kompilator:

struct test_32 {
    int a;      // 4 byte
    short b;    // 2 byte
    int c;      // 4 byte    
} str_32;

Vi kan förvänta oss att denna struct att innehålla 10 byte minne, men genom utskriftsstorlekof sizeof(str_32) ser vi att den använder 12 byte.

Detta hände eftersom kompilatorn justerar variabler för snabb åtkomst. Ett vanligt mönster är att när bastypen upptar N-byte (där N är en effekt på 2, såsom 1, 2, 4, 8, 16 - och sällan någon större), bör variabeln justeras på en N-byte-gräns ( ett multipel av N-byte).

För strukturen som visas med sizeof(int) == 4 och sizeof(short) == 2 , är en vanlig layout:

  • int a; lagrad vid förskjutning 0; storlek 4.
  • short b; lagrad vid offset 4; storlek 2.
  • namngiven polstring vid offset 6; storlek 2.
  • int c; lagrad vid offset 8; storlek 4.

Således upptar struct test_32 12 byte minne. I det här exemplet finns det ingen bakre stoppning.

Kompilatorn kommer att se till att alla struct test_32 variabler lagras med början på en 4-byte gräns, så att medlemmarna i strukturen kommer att justeras korrekt för snabb åtkomst. Minnesallokeringsfunktioner såsom malloc() , calloc() och realloc() krävs för att säkerställa att pekaren som returneras är tillräckligt väl inriktad för användning med vilken datatyp som helst, så dynamiskt allokerade strukturer kommer också att justeras korrekt.

Du kan sluta med udda situationer, till exempel på en 64-bitars Intel x86_64-processor (t.ex. Intel Core i7 - en Mac som kör macOS Sierra eller Mac OS X), där kompilatorerna placerar double inriktat på en 64-bitars-läge 4-byte gräns; men på samma hårdvara, när kompilering i 64-bitars-läge, placerar kompilatorerna double på en 8-byte gräns.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow