W języku C struktury (struct) mogą zawierać inne struktury oraz różne typy danych. Jednak ułożenie pól wewnątrz struktury może wpływać na jej rozmiar i wyrównanie. Kompilator dodaje dodatkowe bajty (padding), aby zapewnić wyrównanie (alignment) w oparciu o największe pole. Jest to ważne dla wydajności i poprawnego działania procesora.
Jeśli struktura zawiera zagnieżdżone struktury, wyrównanie stosuje się rekurencyjnie:
#pragma pack w MSVC lub atrybutu __attribute__((packed)) w GCC/Clang).Przykład:
#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 ", sizeof(struct Inner)); printf("sizeof(struct Outer) = %zu ", sizeof(struct Outer)); return 0; } // sizeof(struct Inner) = 8 (na 64-bit), sizeof(struct Outer) = 16 lub 24
Użycie pack i packed zmniejsza rozmiar kosztem ignorowania wyrównania, ale może to wpłynąć na wydajność lub powodować błędy na niektórych platformach (ARM, DSP itd.).
Pytanie: Czy można zagwarantować taki sam rozmiar tej samej struktury na wszystkich platformach?
Odpowiedź: Nie! Standard C nie gwarantuje tego samego wyrównania, kolejności bajtów (endian), i może "dodać" padding między polami i na końcu struktury. Aby zapewnić zgodność binarną struktur, należy ręcznie zarządzać wyrównaniem i zawsze jawnie testować sizeof na każdej docelowej platformie.
Przykład:
struct Data { char c; int x; }; // sizeof(Data) zazwyczaj 8 na 64-bit, 5 lub 8 na 32-bit
Historia
Przy wymianie struktury między mikrokontrolerem (ARM) a PC poprzez protokół binarny dane przychodzące z ARM nie zgadzały się z oczekiwaniami na PC — z powodu różnego paddingu i kolejności bajtów. W efekcie dekodowane były nieprawidłowe parametry, co prowadziło do fizycznych błędów w sterowaniu urządzeniem.
Historia
W protokole sieciowym w celu przyspieszenia wysyłania danych dodano packed-struktury, ale nie uwzględniono, że na platformie bez wyrównania poszczególne pola nie działały (procesor nie wspierał niewyrównanego dostępu). Efekt: wyjątki sprzętowe podczas pracy z pakietami sieciowymi.
Historia
Serwer pracował z zewnętrznym plikiem składającym się z rekordów struktury. Po aktualizacji kompilatora rozmiar struktury się zmienił (inne wyrównanie). Stare dane w pliku przestały być poprawnie odczytywane, część informacji stała się "uszkodzona".