如何检查已编译类型的表示?
How can I inspect the representation of a compiled type?
The nomicon 提供了一种有趣的方式来显示结构最终将如何在内存中布局。它还表示,对于默认表示,不提供任何保证。虽然我可以使用 std::mem::align_of
和 std::mem::size_of
检查对齐方式和大小,但有没有办法获得 Rust 布置我的 struct/enum 的确切方式,例如带有字段名称和偏移量的 table?
您可以使用编译器标志 --print-type-sizes
(每晚需要)。如果使用 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)
。因此,它也不需要使用类型。
The nomicon 提供了一种有趣的方式来显示结构最终将如何在内存中布局。它还表示,对于默认表示,不提供任何保证。虽然我可以使用 std::mem::align_of
和 std::mem::size_of
检查对齐方式和大小,但有没有办法获得 Rust 布置我的 struct/enum 的确切方式,例如带有字段名称和偏移量的 table?
您可以使用编译器标志 --print-type-sizes
(每晚需要)。如果使用 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)
。因此,它也不需要使用类型。