Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I inspect the representation of a compiled type?

Tags:

memory

rust

The nomicon gives an interesting way of displaying how a struct will eventually be laid out in memory. It also says that for the default representation, no guarantees are made. While I can check alignment and size using std::mem::align_of and std::mem::size_of, is there a way of getting the exact way that Rust has laid out my struct/enum, e.g. a table with field names and offsets?

like image 364
tifrel Avatar asked Oct 27 '25 07:10

tifrel


1 Answers

You can use the compiler flag --print-type-sizes (requires nightly). If using Cargo, use cargo rustc (note it requires cargo clean, thanks @tifrel):

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

E.g.:

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

Output (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

There are some hidden types from main(), and our type. We can see it is 8 bytes, with 4 bytes alignment (because of the i32). We can also see the compiler reordered the fields so that the i16 comes last, and then 2 padding bytes. Note that it prints only used types (this is why we used it in main()), and prints monomorphized types (after generics are applied).

Another way to print more verbose and more specific type information, is to use the perm-unstable rustc_layout attribute:

#![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

Note however this prints the unmonomorphized types, so struct Foo<T>(T) will print layout error: Unknown(T). Because of that, it also doesn't require the type to be used.

like image 85
Chayim Friedman Avatar answered Oct 28 '25 22:10

Chayim Friedman