Usa struct Alignment and Padding in C

Jinku Hu 12 ottobre 2023
  1. Comprendere le basi dell’allineamento e del riempimento in C
  2. Utilizzare la tecnica di riordino dei membri per risparmiare spazio negli oggetti in C
Usa struct Alignment and Padding 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
Autore: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Articolo correlato - C Struct