Usa struct Alignment and Padding in C
- Comprendere le basi dell’allineamento e del riempimento in C
- Utilizzare la tecnica di riordino dei membri per risparmiare spazio negli oggetti in C
Questo articolo spiegherà diversi metodi su come usare l’allineamento e il riempimento di struct
in C.
Comprendere le basi dell’allineamento e del riempimento in C
Tutti gli oggetti in memoria sono rappresentati come i tipi di dati primari come: char
, short
, int
, long
, pointer
ecc. Questi tipi di dati hanno la dimensione corrispondente in memoria. Sulla maggior parte dei moderni processori desktop a 64 bit, le dimensioni sono 1 byte per un char
, 2 byte per un short
, 4 byte per un int
, 8 byte per un pointer
e così via. Nota che queste non sono dimensioni garantite (eccetto per char
), ma si può recuperare la dimensione dell’oggetto usando l’operatore sizeof
. Ora, l’allineamento è il metodo utilizzato dai compilatori per posizionare le variabili nella memoria, il che implica che ogni tipo di dati di base è memorizzato all’indirizzo divisibile per la dimensione corrispondente.
Di solito, l’allineamento viene utilizzato per accedere agli oggetti dati in modo più rapido ed efficiente. L’allineamento forza i diversi tipi di dati dichiarati continuamente a includere una certa spaziatura tra i loro indirizzi. Vale a dire, se dichiariamo una struttura st1
con un puntatore e un char
come mostrato nell’esempio seguente, occuperà 16 byte in totale. Attenzione però, un singolo puntatore richiede 8 byte e un char
richiede un byte, quindi si potrebbe pensare che la struttura st1
debba occupare 9 byte. Ma si comporta come se tutti i membri fossero allineati alla dimensione del membro più grande (cioè 8 byte). La struttura st2
mostra una struttura simile che occupa la stessa quantità di memoria, tranne per il fatto che ha un array di 7 membri char
.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
typedef struct {
char *p;
char c2;
} st1;
typedef struct {
char *p;
char c2;
char padding[7];
} st2;
printf("sizeof st1 = %zu\n", sizeof(st1));
printf("sizeof st2 = %zu\n", sizeof(st2));
exit(EXIT_SUCCESS);
}
Produzione:
sizeof st1 = 16
sizeof st2 = 16
Utilizzare la tecnica di riordino dei membri per risparmiare spazio negli oggetti in C
L’esempio precedente dimostra che c’è un po’ di spreco di memoria quando le strutture includono tipi diversi e non riempiono i confini di allineamento. Tuttavia, in alcuni casi potrebbe essere possibile riordinare i membri della struttura e risparmiare spazio aggiuntivo.
Il codice di esempio successivo definisce la struttura foo1
che ha il membro più grande (char *
) nel mezzo e foo2
con lo stesso membro del primo. Le dimensioni di questi due oggetti sono diverse: 24 byte e 16 byte. Ciò ha a che fare con l’ordinamento dei membri di dati. Nella struttura foo1
, p
deve essere allineato all’indirizzo che è divisibile per 8, quindi int
e short
prima occuperanno 8 byte in totale e due char *
dopo occuperanno anche gli 8 byte. Sebbene, se spostiamo la p
al primo posto, i seguenti membri si comprimeranno negli 8 byte e anche la regola di allineamento sarà soddisfatta. Quindi, la dimensione di foo2
ammonta a 16 byte e viene chiamato per essere compresso struct
. Notare che il compilatore gcc
ha lo speciale specificatore __attribute__ ((packed))
che può forzare la compressione anche dei membri struct
non ordinati.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
typedef struct {
int n1;
short s1;
char *p;
char c1;
char c2;
} foo1;
typedef struct {
char *p;
int n1;
short s1;
char c1;
char c2;
} foo2;
typedef struct {
int n1;
short s1;
char *p;
char c1;
char c2;
} __attribute__((packed)) foo3;
printf("sizeof foo1 = %zu\n", sizeof(foo1));
printf("sizeof foo2 = %zu\n", sizeof(foo2));
printf("sizeof foo3 = %zu\n", sizeof(foo3));
exit(EXIT_SUCCESS);
}
Produzione:
sizeof foo1 = 24
sizeof foo2 = 16
sizeof foo3 = 16
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook