问题
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