Struktury a data na disku
-=-=-=-=-=-=-=-=-=-=-=-=-=-
The world is coming to an end--save your buffers!
Protože jsou typy jinak dlouhé, má to logicky dopad na velikost
struktur, které se často ukládají na disk. Soubory uložené kódem
z jednoho překladače pak nenačtete kódem z druhého. Navíc ale
GCC struktury zarovnává. Od 486 se pro 32 bitové hodnoty uložené
na adresách dělitelných 4 použije 32 bitový přístup. Pokud adresy
dělitelné nejsou, použije se pomalejší přístup. Proto se GCC snaží
všechny 32 bitové hodnoty držet na adresách dělitelných číslem 4,
a 16ti bitové hodnoty na adresách dělitelných číslem 2.
Protože ale norma nedovoluje přeházet položky ve strukturách,
GCC prostě před každou položku přidá volné místo tak, aby
adresa byla správně dělitelná v případě, že začátek struktury
leží na adrese dělitelné 4. Aby toto bylo zaručeno, zvětší ještě
strukturu tak, aby její celková velikost byla násobek 4, aby i pole
struktur bylo správně zarovnané. Aby i začátky pole byly správně
zarovnané, i funkce pro alokaci paměti (malloc atd.) vrací adresy
dělitelné 4. Díky tomu například struktura:
struct {
char a;
char b;
int c;
};
má velikost 8. A se uloží na začátek, b hned za něj. Potom se
dva bajty vynechají, aby byla adresa c dělitelná 4 a pak se uloží 4
bajtová hodnota C. Struktura je tedy stejná, jako:
struct {
char a;
char b;
short unused;
int c;
};
Naopak ale struktura:
struct {
char a;
int c;
char b;
};
zabírá celých 12 bajtů, protože za prvním charem se vynechají
3 bajty pro zarovnání intu, a za posledním další 3 pro zarovnání
velikosti struktury. Proto je ve strukturách dobré řadit položky
podle velikosti. Ušetří se tím nějaké místo v paměti.
Pokud tuto funkci potřebujete vypnout - potřebujete strukturu
načítat z disku tak, aby sedla se starou, nebo se bavit s vnejším
světem, je nutné nastavit atribut packed:
struct {
char a;
int c;
char b;
} __attribute__ ((packed));
Tato struktura má potom velikost 6. Navíc lze tento atribut
použít uprostřed struktury, pokud je třeba pouze nějaký prvek
"připlácnout" hned za předchozí:
struct {
char a;
int c __attribute__ ((packed));
char b;
}
Toto zarovnávání lze také určovat explicitně pomocí atributu
aligned:
struct {
char a;
int c __attribute__ ((aligned (16)));
char b;
}
Tady se int zarovná na 16 bajtů (stejně jako velikost celé
struktury, aby to platilo i v poli). Velikost struktury tedy bude 32.
Tyto atributy lze používat i na normální proměné, pokud to je
třeba.
výheň