Что такое выравнивание структур в C++
Что проверяют
Понимаете ли вы, что раскладку структуры в памяти определяет не порядок строк в тексте, а требования выравнивания, и умеете ли этим управлять. Заодно проверяется, сможете ли вы объяснить, почему sizeof больше суммы размеров полей.
Как отвечать
У каждого типа есть требование выравнивания: адрес объекта обязан быть кратен alignof(T). У структуры выравнивание равно наибольшему среди её членов, поэтому компилятор вставляет пропуски между полями и добивает хвост, чтобы в массиве следующий элемент тоже лёг корректно. Отсюда правило: sizeof всегда кратен alignof.
struct A { char a; int b; char c; }; // 12
struct B { int b; char a; char c; }; // 8Порядок полей по убыванию выравнивания сокращает структуру, не меняя ни строчки логики. Инструменты, которые уместно назвать: alignof и alignas, offsetof для проверки раскладки, #pragma pack и его цена, выравнивание по кэш-линии против ложного разделения между потоками.
Практический вывод для C++ важнее цифр: невыровненный доступ это не просто медленнее, это неопределённое поведение. Поэтому произвольный указатель на буфер нельзя приводить к указателю на структуру, а разбор бинарного формата делается через memcpy в объект.
Где спотыкаются
Считают sizeof суммой размеров полей и удивляются пропускам. Ещё чаще путают выравнивание с упаковкой: упаковка убирает дыры, но взамен даёт невыровненные поля, и на части платформ это стоит дороже сэкономленных байтов, а брать указатель на такое поле уже нельзя.
Считают раскладку универсальной. Она зависит от архитектуры, разрядности и соглашений конкретного компилятора, поэтому структуру нельзя писать в файл или отправлять по сети целиком: обмен идёт через явную сериализацию поле за полем.
Борются за байты там, где памяти хватает, и не смотрят туда, где выигрыш настоящий. Экономия заметна на массиве из миллионов элементов и на попадании горячих полей в одну кэш-линию, а в одиночном объекте разница не видна ни в профиле, ни в счёте за сервер.