Как я могу проверить представление скомпилированного типа?

номикон дает интересный способ отображения того, как структура в конечном итоге будет размещена в памяти. Там же сказано, что для представления по умолчанию никаких гарантий не дается. Хотя я могу проверить выравнивание и размер с помощью std::mem::align_of и std::mem::size_of, есть ли способ получить точный способ, которым Rust изложил мою структуру/перечисление, например. таблица с именами полей и смещениями?

Вы имеете в виду во время выполнения или как пользователь, который вызывает компилятор (для печати в терминале)?

Chayim Friedman 20.03.2022 20:50

Предпочтительно во время выполнения, но я просто подумал, что мне может потребоваться копаться в сгенерированной сборке.

tifrel 20.03.2022 20:52

Вы не можете использовать информацию во время выполнения (она стирается), но вы можете заставить компилятор распечатать ее для вас во время сборки.

Chayim Friedman 20.03.2022 20:53

Это достаточно хорошо, как мне это сделать?

tifrel 20.03.2022 20:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать флаг компилятора --print-type-sizes (требуется nightly). Если вы используете Cargo, используйте cargo rustc (обратите внимание, что для этого требуется cargo clean, спасибо @tifrel):

cargo +nightly rustc -- -Zprint-type-sizes

Например.:

struct Foo(i16, i32);
fn main() { _ = Foo(0, 0); }

Выход (rustc +nightly -Zprint-type-sizes file.rs):

print-type-size type: `Foo`: 8 bytes, alignment: 4 bytes
print-type-size     field `.1`: 4 bytes
print-type-size     field `.0`: 2 bytes
print-type-size     end padding: 2 bytes
print-type-size type: `[closure@std::rt::lang_start<()>::{closure#0}]`: 8 bytes, alignment: 8 bytes
print-type-size     end padding: 8 bytes
print-type-size type: `std::result::Result<isize, !>`: 8 bytes, alignment: 8 bytes
print-type-size     variant `Ok`: 8 bytes
print-type-size         field `.0`: 8 bytes
print-type-size type: `std::process::ExitCode`: 4 bytes, alignment: 4 bytes
print-type-size     field `.0`: 4 bytes
print-type-size type: `std::sys::windows::process::ExitCode`: 4 bytes, alignment: 4 bytes
print-type-size     field `.0`: 4 bytes

Есть некоторые скрытые типы из main() и наш тип. Мы видим, что это 8 байтов с выравниванием по 4 байтам (из-за i32). Мы также можем видеть, что компилятор переупорядочил поля так, чтобы i16 стоял последним, а затем 2 байта заполнения. Обратите внимание, что он печатает только используемые типы (поэтому мы использовали его в main()) и печатает мономорфные типы (после применения дженериков).

Другой способ вывести более подробную и конкретную информацию о типе — использовать атрибут perm-unstable rustc_layout:

#![feature(rustc_attrs)]
#[rustc_layout(debug)]
struct Foo(i16, i32);
fn main() {}
error: layout_of(Foo) = Layout {
           fields: Arbitrary {
               offsets: [
                   Size {
                       raw: 4,
                   },
                   Size {
                       raw: 0,
                   },
               ],
               memory_index: [
                   1,
                   0,
               ],
           },
           variants: Single {
               index: 0,
           },
           abi: ScalarPair(
               Scalar {
                   value: Int(
                       I32,
                       true,
                   ),
                   valid_range: 0..=4294967295,
               },
               Scalar {
                   value: Int(
                       I16,
                       true,
                   ),
                   valid_range: 0..=65535,
               },
           ),
           largest_niche: None,
           align: AbiAndPrefAlign {
               abi: Align {
                   pow2: 2,
               },
               pref: Align {
                   pow2: 3,
               },
           },
           size: Size {
               raw: 8,
           },
       }
 --> rs.rs:3:1
  |
3 | struct Foo(i16, i32);
  | ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Однако обратите внимание, что это печатает немономорфные типы, поэтому struct Foo<T>(T) будет печатать layout error: Unknown(T). Из-за этого он также не требует использования типа.

Я не могу отредактировать ваш ответ, но я думаю, вы должны предупредить, что использование cargo +nightly rust -- ... потребует предыдущего cargo clean или не выдаст информацию.

tifrel 20.03.2022 21:32

Да, хороший момент. Будет редактировать.

Chayim Friedman 20.03.2022 21:33

Помимо благодарности за отличный ответ, означает ли perm-unstable просто то, что он нестабилен, и команда Rust решила никогда его не стабилизировать?

tifrel 20.03.2022 21:38

Да, потому что он используется в основном для отладки самого компилятора и может быть полезен разработчикам, отлаживающим свои приложения, но это не то, что вам следует использовать в рабочей среде.

Chayim Friedman 20.03.2022 21:39

«и может быть полезно для разработчиков, отлаживающих свои приложения, но это не то, что вы должны использовать в производстве», даже тогда это кажется действительно изворотливым, если вы не пытаетесь выделить поля, которыми манипулируют, из списков сборок.

Masklinn 21.03.2022 11:37

Другие вопросы по теме