我使用 Rust 一段时间了,几乎从未见过任何带有#[repr(C)]
. #[repr(C)]
但是,我在 Solana 程序库中看到了很多(例如,这里是spl-token
程序源代码)。
在阅读 Rust Reference 的“类型布局”一章(尤其是“Rust
表示”部分)后,我仍然对 Rust 究竟如何进行数据布局感到困惑。医生说:
这种表示形式所做的唯一数据布局保证是健全性所需的数据布局。他们是:
- 这些字段已正确对齐。
- 这些字段不重叠。
- 类型的对齐方式至少是其字段的最大对齐方式。
似乎C
代表也满足这些保证。但C
表征被详细描述,而Rust
表征却没有。所以我不太明白这两种表示之间的区别。Rust 编译器是否会进行一些复杂的优化,例如修改我的原始结构定义以使其节省空间?由于优化太复杂,文档只是省略了细节?
我的正式问题是:
- Rust 表示与 C 表示(对于结构和枚举,以及可能的其他数据复合结构)究竟有何不同?
#[repr(C)]
为什么有人在开发“普通”Rust 程序时会使用它?我所说的“正常”是指该程序不涉及互操作,也不涉及交叉编译(到另一个目标,如 Solana)。- 为什么 Solana 开发团队总是添加
#[repr(C)]
结构体和枚举?
它的主要不同之处在于它是未定义的,因此编译器团队让自己有机会随时更改它。据我所知,目前它所做的就是重新排序字段,以最小化填充(从而最小化总结构大小),而
repr(C)
将按定义顺序放置内存(只需在必要时添加填充)。这样做的原因之一是,精确控制位置和填充对于解决诸如错误共享之类的问题非常重要,其中同一缓存行上的数据会发生冲突并降低性能,或者为了确保特定成员的对齐。
它也与动态链接库或零拷贝序列化等相关,因为您需要能够同步精确的内存布局。
repr(Rust)
意味着你不知道(从某种意义上说,它不能得到保证,并且理论上可能随时发生变化)。虽然我猜这些可以算作互操作,但它们不会跨越 FFI 边界或任何东西。你得问他们。