有没有更安全的方法使用联合在整数和浮点数之间进行转换?

Is there a safer way to use unions to convert between integer and floating-point numbers?

我正在用 Rust 编写 VM,我有 C 和 C++ 背景。我需要类似联合的功能,因为在 VM 堆栈上我可以存储 intfloat

在 C 中我有一个工会:

union stack_record_t {
    int i;
    float f;
};

我可以将记录用作 intfloat,且运行时开销为零。我有一个静态字节码分析器,它会在字节码执行之前发现类型错误,所以我不必在记录旁边存储一个标志。

我不知道在 Rust 中使用联合是否是个好主意,因为它们不安全。在 Rust 中有没有安全的方法来做到这一点——而且成本为零? 我应该只使用不安全的 Rust 联合吗?

您可以使用 f32::from_bits and to_bits 安全地将 u32 的原始位重新解释为 f32,反之亦然。这是一个 "free" 转换 - 它编译为无代码(启用优化)。¹要在 u32i32 之间转换,您可以使用 as 强制转换,它们同样用于更改签名时免费。

在我看来,u32 是这里的共同点,因此您可以考虑制作一个包含 u32struct 并公开获取或设置适当类型的方法:

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();
    }
}

Compare the generated code.

另请参阅

  • Is it possible to write Quake's fast InvSqrt() function in Rust?

¹ 这些函数在内部使用 transmute,它会像使用联合一样重新解释这些位。所以当它们被优化器内联时,生成的代码是相同的。