其他分享
首页 > 其他分享> > Rust 中的数据布局--可选的数据布局

Rust 中的数据布局--可选的数据布局

作者:互联网

 

Rust 允许你指定不同于默认的数据布局策略,并为你提供了不安全代码指南

repr(C)

这是最重要的“repr”。它的意图相当简单:做 C 所做的事。字段的顺序、大小和对齐方式与你在 C 或 C++ 中期望的完全一样。任何你期望通过 FFI 边界的类型都应该有repr(C),因为 C 是编程世界的语言框架。这对于合理地使用数据布局做更多的技巧也是必要的,比如将值重新解释为不同的类型。

我们强烈建议使用rust-bindgen和/或cbindgen来为你管理 FFI 的边界。Rust 团队与这些项目紧密合作,以确保它们能够稳健地工作,并与当前和未来关于类型布局和 reprs 的保证兼容。

必须记住repr(C)与 Rust 更奇特的数据布局功能的互动。由于它具有“用于 FFI”和“用于布局控制”的双重目的,repr(C)可以应用于那些如果通过 FFI 边界就会变得无意义或有问题的类型:

repr(transparent)

这只能用于具有单个非零尺寸字段的结构(可能还有其他零尺寸字段)。其效果是,整个结构的布局和 ABI 被保证与该字段相同。

我们的目标是使单一字段和结构之间的转换成为可能。一个例子是UnsafeCell,它可以被转换为它所包装的类型。(UnsafeCell也用了一个不稳定的特性no_niche,所以当它嵌套其它类型的时候,它的 ABI 也并没有一个稳定的保证。)

另外,通过 FFI 传递结构,其中内部字段类型在另一端被期望,这保证了结构的工作。特别是,这对于struct Foo(f32)总是具有与f32相同的 ABI 是必要的。

只有在唯一的字段为pub或其内存布局在文档中所承诺的情况下,该 repr 才被视为一个类型的公共 ABI 的一部分。否则,该内存布局不应被其他 crate 所依赖。

更多细节可以参考RFC

repr(u*), repr(i*)

这些指定了使无字段枚举的大小。如果判别符超过了它可以容纳的整数,就会产生一个编译时错误。你可以通过将溢出的元素明确设置为 0 来手动要求 Rust 允许这样做。

术语“无字段枚举”仅意味着该枚举在其任何变体中都没有数据。没有repr(u*)repr(C)的无字段枚举仍然是一个 Rust 本地类型,没有稳定的 ABI 表示。添加repr会使它在 ABI 上被视为与指定的整数大小完全相同。

如果枚举有字段,其效果类似于repr(C)的效果,因为该类型有一个定义的布局。这使得将枚举传递给 C 代码或者访问该类型的原始表示并直接操作其标记和字段成为可能,详见RFC

这些“repr”对结构(struct)没有作用。

在含有字段的枚举中加入明确的repr(u*)repr(i*)repr(C)可以抑制空指针优化,比如:

 

enum MyOption<T> {
    Some(T),
    None,
}

#[repr(u8)]
enum MyReprOption<T> {
    Some(T),
    None,
}

assert_eq!(8, size_of::<MyOption<&u16>>());
assert_eq!(16, size_of::<MyReprOption<&u16>>());

空指针优化针对无字段且拥有repr(u*)repr(i*)repr(C)的枚举仍然生效。

repr(packed)

repr(packed)强制 Rust 去掉任何填充,只将类型对齐到一个字节。这可能会改善内存占用,但可能会有其他负面的副作用。

特别是,大多数架构强烈地希望数值被对齐。这可能意味着不对齐的加载会受到惩罚(x86),甚至会出现故障(一些 ARM 芯片)。对于简单的情况,如直接加载或存储一个已打包的字段,编译器可能能够用移位和掩码来解决对齐问题。然而,如果你对一个已打包的字段进行引用,编译器就不太可能发出代码来避免无对齐的加载。

由于这可能导致未定义的行为,我们在 Lint 中已经实现了对应的检查,并且该行为会被认为是错误。

repr(packed)是不能轻易使用的,除非你有极端的要求,否则不应该使用这个。

这个 repr 是对repr(C)repr(Rust)的修改。

repr(align(n))

repr(align(n))(其中n是 2 的幂)强制类型至少按照 n 对齐。

这可以实现一些技巧,比如确保数组中的相邻元素不会彼此共享同一个缓存行(这可能会加快某些类型的并发代码)。

这是repr(C)repr(Rust)的一个修改版本,它与repr(packed)不兼容。

标签:--,ABI,布局,repr,枚举,FFI,类型,Rust
来源: https://www.cnblogs.com/horysk/p/16071008.html