О типах структур
1. Именованная структура (
struct Point { x: i64, y: i32 })- Размер: 16 байт. Выравнивание: 8 байт.
- Физика компилятора: Так как указан дефолтный
#[repr(Rust)], компилятор выполняет автоматический реордеринг полей (Field reordering). В зависимости от флагов оптимизации (-C opt-level=3), он почти гарантированно переставит поля как[y (4 байта), padding (4 байта), x (8 байт)], чтобы минимизировать общий размер типа, если в структуре много разнородных полей. - Взаимодействие с перечислениями: Если мы обернем эту структуру в
Option<Point>, размер типа вырастет до 24 байт. Почему? Потому что уPointнет свободных битовых комбинаций (ниши) внутри валидных значенийi64иi32. Компилятору приходится выделять отдельный байт под тег дискриминанта (Some/None) и выравнивать всю конструкцию до границы 8 байт.
2. Кортежная структура (
struct Color(i32, u8, i32))- Размер: 12 байт. Выравнивание: 4 байта.
- Физика компилятора: Чистый вес данных — 9 байт. По правилам процессорной архитектуры x86_64, невыровненный доступ к памяти (Misaligned access) карается падением производительности из-за чтения нескольких кэш-линий (Cache lines) за раз. Поэтому
rustcжестко бьет размер по границе кратности максимального выравнивания поля (4 байта). 9 округляется вверх до 12. Паддинг — 3 байта. - Опровержение догм: Порядок полей
.0,.1,.2внутри бинарника не гарантирован. Компилятор сожмет структуру в последовательность[.0 (4B), .2 (4B), .1 (1B), padding (3B)]. Разницы в памяти между именованной и кортежной структурой на уровне машинного кода нет вообще — генерируются идентичные ASM-инструкции смещения относительно указателя базы.
3. Единичная структура (
struct Electron)- Размер: 0 байт. Выравнивание: 1 байт.
- Физика под капотом (То, что упускают учебники): Да, она занимает 0 байт. Но как она ведет себя внутри других контейнеров?
Option<Electron>занимает 0 байт в памяти. Компилятор применяет нишевую оптимизацию: так как уElectronровно одно валидное состояние (оно само), компилятору вообще не нужны биты, чтобы отличитьSome(Electron)отNoneна этапе выполнения.- Если единичная структура является последним полем в
#[repr(C)]структуре, ее размер в Си-контексте может стать равным 1 байту, чтобы предотвратить совпадение адресов двух разных объектов в памяти, что запрещено стандартом POSIX/C. Но в чистом Rust (repr(Rust)) размер остается строго нулевым. - Адресация: Вызов
&Electronне генерирует обращений к TLB (Translation Lookaside Buffer) или страницам памяти. Компилятор подставляет константу0x1(или другое значение, соответствующее выравниванию) прямо в регистр. Это легальный «виртуальный» адрес, который никогда не разыменовывается процессором физически.
Если мы добавим к любой из этих структур атрибут
#[repr(C)], автоматическая оптимизация памяти отключается. Компилятор будет обязан располагать поля строго в том порядке, в котором они написаны в исходном коде, и вставлять паддинг по правилам платформенного ABI (Application Binary Interface).sdmrnv [2.68ms]
