有没有更安全的方法使用联合在整数和浮点数之间进行转换?
Is there a safer way to use unions to convert between integer and floating-point numbers?
我正在用 Rust 编写 VM,我有 C 和 C++ 背景。我需要类似联合的功能,因为在 VM 堆栈上我可以存储 int
或 float
。
在 C 中我有一个工会:
union stack_record_t {
int i;
float f;
};
我可以将记录用作 int
或 float
,且运行时开销为零。我有一个静态字节码分析器,它会在字节码执行之前发现类型错误,所以我不必在记录旁边存储一个标志。
我不知道在 Rust 中使用联合是否是个好主意,因为它们不安全。在 Rust 中有没有安全的方法来做到这一点——而且成本为零?
我应该只使用不安全的 Rust 联合吗?
您可以使用 f32::from_bits
and to_bits
安全地将 u32
的原始位重新解释为 f32
,反之亦然。这是一个 "free" 转换 - 它编译为无代码(启用优化)。¹要在 u32
和 i32
之间转换,您可以使用 as
强制转换,它们同样用于更改签名时免费。
在我看来,u32
是这里的共同点,因此您可以考虑制作一个包含 u32
的 struct
并公开获取或设置适当类型的方法:
pub struct Record(u32);
impl Record {
fn get_int(&self) -> i32 {
self.0 as _
}
fn get_float(&self) -> f32 {
f32::from_bits(self.0)
}
fn set_int(&mut self, value: i32) {
self.0 = value as _;
}
fn set_float(&mut self, value: f32) {
self.0 = value.to_bits();
}
}
另请参阅
- Is it possible to write Quake's fast InvSqrt() function in Rust?
¹ 这些函数在内部使用 transmute
,它会像使用联合一样重新解释这些位。所以当它们被优化器内联时,生成的代码是相同的。
我正在用 Rust 编写 VM,我有 C 和 C++ 背景。我需要类似联合的功能,因为在 VM 堆栈上我可以存储 int
或 float
。
在 C 中我有一个工会:
union stack_record_t {
int i;
float f;
};
我可以将记录用作 int
或 float
,且运行时开销为零。我有一个静态字节码分析器,它会在字节码执行之前发现类型错误,所以我不必在记录旁边存储一个标志。
我不知道在 Rust 中使用联合是否是个好主意,因为它们不安全。在 Rust 中有没有安全的方法来做到这一点——而且成本为零? 我应该只使用不安全的 Rust 联合吗?
您可以使用 f32::from_bits
and to_bits
安全地将 u32
的原始位重新解释为 f32
,反之亦然。这是一个 "free" 转换 - 它编译为无代码(启用优化)。¹要在 u32
和 i32
之间转换,您可以使用 as
强制转换,它们同样用于更改签名时免费。
在我看来,u32
是这里的共同点,因此您可以考虑制作一个包含 u32
的 struct
并公开获取或设置适当类型的方法:
pub struct Record(u32);
impl Record {
fn get_int(&self) -> i32 {
self.0 as _
}
fn get_float(&self) -> f32 {
f32::from_bits(self.0)
}
fn set_int(&mut self, value: i32) {
self.0 = value as _;
}
fn set_float(&mut self, value: f32) {
self.0 = value.to_bits();
}
}
另请参阅
- Is it possible to write Quake's fast InvSqrt() function in Rust?
¹ 这些函数在内部使用 transmute
,它会像使用联合一样重新解释这些位。所以当它们被优化器内联时,生成的代码是相同的。