如何检查编译类型的表示?

til*_*boy 3 memory rust

注释提供了一种有趣的方式来显示结构最终如何在内存中布局。它还表示,对于默认表示,不提供任何保证。虽然我可以使用std::mem::align_ofand检查对齐和大小std::mem::size_of,但有没有办法获得 Rust 布局我的结构/枚举的确切方式,例如带有字段名称和偏移量的表?

Cha*_*man 5

您可以使用编译器标志--print-type-sizes(需要每晚)。如果使用 Cargo,请使用cargo rustc(注意它需要cargo clean,谢谢@tifrel):

cargo +nightly rustc -- -Zprint-type-sizes
Run Code Online (Sandbox Code Playgroud)

例如:

struct Foo(i16, i32);
fn main() { _ = Foo(0, 0); }
Run Code Online (Sandbox Code Playgroud)

输出 (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
Run Code Online (Sandbox Code Playgroud)

有一些来自main()和我们的类型的隐藏类型。我们可以看到它是 8 个字节,有 4 个字节对齐(因为i32)。我们还可以看到编译器对字段进行了重新排序,使得i16位于最后,然后是 2 个填充字节。请注意,它仅打印使用过的类型(这就是我们在 中使用它的原因main()),并打印单态类型(在应用泛型之后)。

打印更详细和更具体的类型信息的另一种方法是使用 perm-unstablerustc_layout属性:

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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

但请注意,这将打印非单态类型,因此struct Foo<T>(T)将打印layout error: Unknown(T)。因此,它也不需要使用类型。