Rust ABI能保证枚举的紧凑性吗?

Rust ABI能保证枚举的紧凑性吗?,rust,Rust,我知道锈ABI不稳定。但是,Rust编译器目前正在执行一些优化,以将字段压缩到标记中: 使用std::mem::size\u of; 枚举节点{ N1_1{ 好吗:布尔, 材料:u32, }, N1_2{ 好吗:布尔, 左:盒子, 右:盒子, }, } 枚举节点2{ N2_1{stuff:u32}, N2_2, } fn main(){ println!(“{:?}{:?}”,大小为::(),大小为::()); } 这将打印24 8。显然,正在发生的是字段被折叠到构造函数标记中。这种行为有保证

我知道锈ABI不稳定。但是,Rust编译器目前正在执行一些优化,以将字段压缩到标记中:

使用std::mem::size\u of;
枚举节点{
N1_1{
好吗:布尔,
材料:u32,
},
N1_2{
好吗:布尔,
左:盒子,
右:盒子,
},
}
枚举节点2{
N2_1{stuff:u32},
N2_2,
}
fn main(){
println!(“{:?}{:?}”,大小为::(),大小为::());
}
这将打印
24 8
。显然,正在发生的是字段被折叠到构造函数标记中。这种行为有保证吗?我不是问具体的内存表示是否会保持不变,而是是否有一个承诺,即在未来某个时间点的大小不会增加

我想不出一个很好的理由来解释为什么他们想在某个时候改变表现形式来增加尺寸,但也许这只是因为我缺乏想象力,所以我正在寻找一个“官方”的答案

链接到GitHub问题/RFC会很有帮助。我试图浏览问题追踪器,但找不到任何东西。我能找到的最接近的东西是一个
bool
大小为1字节,这不是保证

这种行为有保证吗

不。锈菌ABI不能保证任何种类,这就是“不稳定”的意思。只要代码能够正常工作,并且ABI之外的其他保证被保留,开发人员就能够以他们认为合适的方式对其进行更改

真的,在这种情况下,你对ABI的关心程度不如你对ABI的关心程度。参考资料说,我的重点是:

没有
repr
属性的标称类型具有默认表示形式。非正式地说,这种表示也称为
rust
表示

此表示法不能保证数据布局

一个很好的理由是,他们可能希望在某个时候更改表示以增加大小

一个可能的原因是因为填充或对齐之类的概念。有人可能(但不太可能)发现,将每个结构与331字节对齐会使代码运行速度加快53倍


rustc+nightly-Zprint类型大小enum-compactness.rs
类型:`Node`:24字节,对齐方式:8字节
鉴别码:1字节
变量'N1_1':7个字节
字段“.is_good”:1字节
填充:2字节
字段`.stuff`:4字节,对齐方式:4字节
变体'N1_2':23字节
字段“.is_good”:1字节
填充:6字节
字段`.left`:8字节,对齐方式:8字节
字段“.right”:8字节
type:`Node2`:8字节,对齐方式:4字节
鉴别码:4字节
变量'N2_1':4个字节
字段“.stuff”:4字节
变量'N2_2':0字节
这种行为有保证吗

不。锈菌ABI不能保证任何种类,这就是“不稳定”的意思。只要代码能够正常工作,并且ABI之外的其他保证被保留,开发人员就能够以他们认为合适的方式对其进行更改

真的,在这种情况下,你对ABI的关心程度不如你对ABI的关心程度。参考资料说,我的重点是:

没有
repr
属性的标称类型具有默认表示形式。非正式地说,这种表示也称为
rust
表示

此表示法不能保证数据布局

一个很好的理由是,他们可能希望在某个时候更改表示以增加大小

一个可能的原因是因为填充或对齐之类的概念。有人可能(但不太可能)发现,将每个结构与331字节对齐会使代码运行速度加快53倍


rustc+nightly-Zprint类型大小enum-compactness.rs
类型:`Node`:24字节,对齐方式:8字节
鉴别码:1字节
变量'N1_1':7个字节
字段“.is_good”:1字节
填充:2字节
字段`.stuff`:4字节,对齐方式:4字节
变体'N1_2':23字节
字段“.is_good”:1字节
填充:6字节
字段`.left`:8字节,对齐方式:8字节
字段“.right”:8字节
type:`Node2`:8字节,对齐方式:4字节
鉴别码:4字节
变量'N2_1':4个字节
字段“.stuff”:4字节
变量'N2_2':0字节

编译器确实通过小生境填充()执行枚举优化,但我不认为您的示例演示了这一点
Node
无法利用小生境填充(如当前实现的),因为它没有任何零大小的变体
Node2
有一个大小为零的变量,但非零大小的变量没有任何无效值可容纳。“字段被折叠到构造函数标记中”是什么意思?@trentcl,由于对齐要求,标记有填充字节。例如,如果我使用了
N1_1(Box,Box
),大小仍然是24个字节,标签有7个字节的填充。
bool
的情况是,一个填充字节被bool替换。尝试使用
#[repr(C)]
时,大小会跳到32。锈迹不会“填充”同级类型的填充字节与另一个类型的值。这将允许对同一内存地址的两个可变引用。我很困惑。在这种情况下,
Node1
的内存布局是什么?@Shepmaster,你能将其添加到你的答案中吗?我明白你的意思,但说标记有填充字节并不准确。vaRIANT中的填充对于不同的变量可能不同,但这是内存布局计算方式的结果。变量中的填充根本不需要与标记相邻,甚至在没有标记的情况下也可能存在。编译器通过小生境填充执行枚举优化
use std::mem::size_of;

enum Node {
    N1_1 {
        is_good: bool,
        stuff: u32,
    },
    N1_2 {
        is_good: bool,
        left: Box<Node>,
        right: Box<Node>,
    },
}

enum Node2 {
    N2_1 { stuff: u32 },
    N2_2,
}

fn main() {
    println!("{:?} {:?}", size_of::<Node>(), size_of::<Node2>());
}