ProgrammazioneProgrammatore di sistema

Spiegare la meccanica delle strutture annidate e dell'allineamento delle strutture in C. Come controllare la dimensione di una struttura e quali problemi possono sorgere?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Nel linguaggio C le strutture (struct) possono includere altre strutture e vari tipi di dati. Tuttavia, la disposizione dei campi all'interno della struttura può influenzare la sua dimensione e l'allineamento. Il compilatore aggiunge byte extra (padding) per rispettare l'allineamento (alignment) del campo più grande. Questo è importante per le prestazioni e il corretto funzionamento del processore.

Se una struttura contiene strutture annidate, l'allineamento si applica in modo ricorsivo:

  • La dimensione della struttura è sempre un multiplo dell'allineamento del campo più grande.
  • Le strutture annidate possono portare a offset inaspettati, a causa dei quali sizeof(struct) è maggiore della somma di sizeof(campi).

Come controllare la dimensione?

  1. Ordinare i campi in base alla dimensione decrescente.
  2. Utilizzare direttive di allineamento (ad esempio, #pragma pack in MSVC o l'attributo __attribute__((packed)) in GCC/Clang).

Esempio:

#include <stdio.h> struct Inner { char c; int x; }; struct Outer { char a; struct Inner b; short s; }; int main() { printf("sizeof(struct Inner) = %zu\n", sizeof(struct Inner)); printf("sizeof(struct Outer) = %zu\n", sizeof(struct Outer)); return 0; } // sizeof(struct Inner) = 8 (su 64 bit), sizeof(struct Outer) = 16 o 24

L'uso di pack e packed riduce la dimensione ignorando l'allineamento, ma può ridurre le prestazioni o causare errori su alcune piattaforme (ARM, DSP, ecc.).


Domanda ingannevole.

Domanda: È possibile garantire la stessa dimensione della stessa struttura su tutte le piattaforme?

Risposta: No! Lo standard C non garantisce lo stesso allineamento, l'ordine dei byte (endian), e può "aggiungere" padding tra i campi e alla fine della struttura. Per la compatibilità binaria delle strutture è necessario utilizzare il controllo manuale dell'allineamento e testare sempre esplicitamente sizeof su ciascuna piattaforma target.

Esempio:

struct Data { char c; int x; }; // sizeof(Data) di solito è 8 su 64 bit, 5 o 8 su 32 bit

Storia

Durante lo scambio di una struttura tra un microcontrollore (ARM) e un PC tramite un protocollo binario, i dati provenienti da ARM non corrispondevano alle aspettative sul PC — a causa di un diverso padding e ordine dei byte. Questo portava a decodificare parametri errati, causando errori fisici nel controllo del dispositivo.


Storia

In un protocollo di rete, per accelerare l'invio dei dati sono state aggiunte strutture packed, ma non si è tenuto conto che su piattaforme senza allineamento alcuni campi non funzionavano (il processore non supportava l'accesso non allineato). Risultato: eccezioni hardware durante l'elaborazione dei pacchetti di rete.


Storia

Un server lavorava con un file esterno composto da registrazioni di struttura. Dopo l'aggiornamento del compilatore, la dimensione della struttura è cambiata (un diverso allineamento). I vecchi dati nel file hanno smesso di essere letti correttamente, parte delle informazioni è diventata "rovinata".