Коротко — по правилам компоновщика/ABI (и так делает компилятор):
- Каждое поле в структуре располагается в порядке объявления, но его смещение (offset) выравнивается так, чтобы быть кратным требуемому выравниванию типа этого поля.
- Требуемое выравнивание (alignment) простых типов обычно равно их размеру (char — 1, short — 2, int — 4, double — 8 и т.п.), но может отличаться в зависимости от платформы/ABI.
- Выравнивание самой структуры равно максимальному выравниванию её полей (если вы явно не изменяли выравнивание с помощью атрибутов/директив).
- Общий размер структуры sizeof(struct) округляется вверх до кратного этому выравниванию (добавляется окончательный padding), чтобы следующий элемент массива структур был корректно выровнен.
Алгоритм (упрощённо):
1. Для каждого поля i: установить его смещение = smallest offset >= current_offset, кратный alignof(type_i). Поместить поле, увеличить current_offset += sizeof(type_i).
2. После всех полей взять struct_align = max(alignof(field_i)). Размер структуры = smallest size >= current_offset, кратный struct_align.
Пример
```
struct TEST {
char c; // align 1
int i; // align 4
short s; // align 2
};
```
Пояснение (типичные 32/64‑битные платформы):
- c на offset 0.
- Для i требуется offset кратный 4 → i будет на offset 4 (между 0 и 4 вставлены 3 байта паддинга).
- После i (занимает 4 байта) current_offset = 8. short требует выравнивания 2 → s может быть на offset 8.
- current_offset после s = 10. struct_align = max(1,4,2) = 4, значит sizeof(struct) округляется до 12 (две байта окончательного паддинга).
Инструменты/операторы в C:
- offsetof(struct_type, member) — смещение поля.
- _Alignof(type) (C11) или GCC/Clang: __alignof__(type) — требуемое выравнивание типа.
- _Alignas(n) (C11) или __attribute__((aligned(n))) — задать выравнивание типа/переменной.
- __attribute__((packed)) или #pragma pack(n) — убрать (уменьшить) паддинг; применять осторожно (возможны невыравненные доступы и «медленная»/неподдерживаемая работа на некоторых архитектурах).
Пример кода, который показывает поведение:
```
#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>
struct TEST { char c; int i; short s; };
int main(void) {
printf("offsetof c=%zu\n", offsetof(struct TEST, c));
printf("offsetof i=%zu\n", offsetof(struct TEST, i));
printf("offsetof s=%zu\n", offsetof(struct TEST, s));
printf("alignof(struct TEST)=%zu\n", alignof(struct TEST));
printf("sizeof(struct TEST)=%zu\n", sizeof(struct TEST));
}
```
Особые случаи:
- bit‑fields: правила зависят от компилятора/ABI (как они упаковываются в базовый целочисленный контейнер, где начинается новый контейнер и т.п.).
- flexible array member (последнее поле типа T[] без размера) не увеличивает выравнивание структуры, но sizeof учитывает только фиксированную часть; выделять память нужно с учётом желаемого числа элементов.
- union: выравнивание union = max выравниваний его членов; sizeof = размер самого большого члена, округлённый до этого выравнивания.
Если нужно — пришлите конкретную структуру (или платформу), я разберу её смещения и размер и покажу варианты с packed/_Alignas.