Как работает выравнивание на примере структуры с двумя int и одним bool в C++
Что проверяют
Понимаете ли вы, откуда в структуре берутся лишние байты, и умеете ли посчитать sizeof в уме. Следом просят переставить поля так, чтобы структура похудела, или спрашивают про #pragma pack и цену невыровненного доступа.
Как отвечать
У каждого типа есть требование к выравниванию alignof(T): адрес объекта должен быть кратен этому числу. На типичных платформах (x86-64, ARM64) int занимает 4 байта с выравниванием 4, а bool 1 байт с выравниванием 1, хотя стандарт эти числа не фиксирует. Компилятор вставляет паддинг по двум правилам:
- перед полем: чтобы смещение поля было кратно его выравниванию;
- в конце структуры: чтобы общий размер был кратен
alignofсамой структуры, то есть наибольшему выравниванию полей. Иначе второй элемент массива таких структур оказался бы невыровненным.
Считаем struct S { int a; int b; bool c; };: a на смещении 0, b на 4, c на 8, итого 9 байт, добиваем до кратного 4 и получаем sizeof(S) == 12. Порядок bool, int, int даёт те же 12, только 3 байта паддинга окажутся после bool, а не в хвосте. Для двух int и bool перестановка не помогает. Выигрыш появляется, когда смешаны типы с разным выравниванием: char, double, char занимает 24 байта, а double, char, char уже 16. Правило: поля по убыванию выравнивания.
Проверять стоит не на глаз, а через sizeof, alignof, offsetof и static_assert. Управлять выравниванием можно через alignas(64), например чтобы развести счётчики разных потоков по кэш-линиям и избежать false sharing, и через #pragma pack(1), которая уберёт паддинг и сделает структуру 9 байт ценой невыровненного доступа.
Где спотыкаются
Называют 16 байт, будто bool тянет за собой выравнивание до 8. Для этой структуры правильный ответ 12.
Забывают про хвостовой паддинг и называют 9, объясняя это тем, что после последнего поля ничего не лежит.
Советуют #pragma pack для экономии памяти без оговорок. Невыровненный доступ на x86 обычно просто медленнее, на некоторых архитектурах вызывает аппаратное исключение, а указатель на поле упакованной структуры легко приводит к неопределённому поведению.