问题
I´m writing a VM in Rust and I have a C and C++ background. I need union-like functionality because on the VM stack I can either store an int or a float.
In C I had a union:
union stack_record_t {
int i;
float f;
};
I can use the record as int or as float with zero runtime overhead. I have a static bytecode analyzer which will find type errors before the bytecode executes, so I don't have to store a flag alongside the record.
I don´t know if it is a good idea to use unions in Rust because they are unsafe. Is there any safe way to do this in Rust - also with zero cost? Should I just use the unsafe Rust unions?
回答1:
You can use f32::from_bits and to_bits to safely reinterpret the raw bits of a u32 as an f32 and vice versa. This is a "free" conversion – it compiles to no code (with optimizations turned on).¹ To convert between u32 and i32 you can use as casts, which are likewise free when used to change signedness.
It seems to me that u32 is the common denominator here, so you might consider making a struct that contains a u32 and exposes methods to get or set the appropriate type:
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.
See Also
- Is it possible to write Quake's fast InvSqrt() function in Rust?
- Is transmuting bytes to a float safe or might it produce undefined behavior?
- Is casting between integers expensive?
¹ These functions use transmute internally, which reinterprets the bits just as using a union would. So when they are inlined by the optimizer the generated code is the same.
来源:https://stackoverflow.com/questions/60930777/is-there-a-safer-way-to-use-unions-to-convert-between-integer-and-floating-point