% Альтернативные представления
Rust позволяет вам определять альтернативные стратегии расположения данных в памяти, отличающиеся от стратегии по умолчанию.
repr(C)
Это самая важная repr
. У нее простая цель: делать то, что делает Си. Порядок,
размер и выравнивание полей полностью соответствуют тому, что вы ожидаете от Си
или C++. Все типы, проходящие через границы FFI, должны иметь repr(C)
. Связано
это с тем, что Си - это лингва-франка в мире программирования. Она также
необходима, чтобы правильно делать некоторые сложные трюки с размещением данных
в памяти вроде интерпретации чисел, как значений других типов.
Но надо держать в голове особенности взаимодействия с более экзотическим
размещением данных Rust в памяти. Из-за своего двойственного назначения - "для
FFI" и "для контроля размещения в памяти", repr(C)
можно применять к типам,
которые нечувствительны или, наоборот, проблемны при прохождении границ
FFI.
-
ТНР не занимают места, даже учитывая, что это не стандартное поведение в Си, и что это явно противоречит поведению пустых типов в C++, которые занимают байт свободного места.
-
ТДР, кортежи и типы-суммы не существуют в Си и, следовательно, всегда являются FFI небезопасными.
-
Кортежные структуры похожи на структуры, если смотреть относительно
repr(C)
, с единственным отличием, заключающимся в отсутствии имен у полей. -
Если у типа есть drop flags, они все равно будут добавлены
-
Для перечислений это эквивалентно одному из
repr(u*)
(смотри следующий раздел). Выбранный размер является размером по умолчанию перечислений для С ABI целевой платформы. Помните, что представление перечислений в Си зависит от реализации, поэтому все это на самом деле только догадка. В частности, это может быть не так, если интересующий код на Си компилировать с определенными флагами.
repr(u8), repr(u16), repr(u32), repr(u64)
Для создания Си-подобных перечислений нужно указать размер. Если дискриминант переполняет целое, в который его нужно уместить, возникнет ошибка компиляции. Вы можете вручную попросить Rust явно заменять переполняющийся элемент на 0. Но Rust не разрешит вам создать перечисление, в котором два варианта будут иметь одинаковый дискриминант.
Для не-Си-подобных перечислений, это запретит выполнять определенные оптимизации, такие как оптимизации нулевого указателя.
Эти представления никак не влияют на структуры.
repr(packed)
repr(packed)
заставит Rust убрать любой паддинг и выравнять тип по байту. Это
улучшит использование памяти, но появятся негативные побочные последствия.
В частности, большинство архитектур строго требуют выравнивать значения. Это означает, что обращение к памяти по невыровненному адресу выполняется дольше (x86), или прервется с ошибкой (на некоторых чипах ARM). Для простых случаев, как прямая загрузка или сохранение упакованного поля, компилятору удастся сгладить проблемы выравнивания сдвигами и масками. Но если вы создадите ссылку на упакованное поле, очень маловероятно, что компилятору удастся избежать невыровненной загрузки.
Для Rust 1.0 это может вызвать неопределенное поведение.
repr(packed)
использовать непросто. Если у вас нет строгих требований, лучше
ее не использовать.
Это - модификатор для repr(C)
и repr(rust)
.