代码之家  ›  专栏  ›  技术社区  ›  tifrel

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

  •  0
  • tifrel  · 技术社区  · 2 年前

    The nomicon 提供了一种有趣的方式来显示结构最终将如何放置在内存中。它还表示,对于默认表示,不作任何保证。而我可以使用 std::mem::align_of std::mem::size_of ,是否有一种方法可以获得Rust对我的结构/枚举进行布局的确切方式,例如一个带有字段名和偏移量的表?

    1 回复  |  直到 2 年前
        1
  •  1
  •   Chayim Friedman    2 年前

    可以使用编译器标志 --print-type-sizes (需要每晚)。如果使用货物,请使用 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 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) .因此,它也不需要使用类型。