Есть ли более безопасный способ использования объединений для преобразования целых чисел в числа с плавающей запятой?

Я пишу виртуальную машину на Rust и имею опыт работы с C и C++. Мне нужна функция объединения, потому что в стеке виртуальных машин я могу хранитьint или float.

В CI был союз:

union stack_record_t {
    int i;
    float f;
};

Я могу использовать запись как int или как floatс нулевыми накладными расходами времени выполнения. У меня есть статический анализатор байт-кода, который находит ошибки типа до выполнения байт-кода, поэтому мне не нужно хранить флаг рядом с записью.

Я не знаю, стоит ли использовать объединения в Rust, потому что они небезопасны. Есть ли безопасный способ сделать это в Rust - также с нулевой стоимостью? Должен ли я просто использовать небезопасные профсоюзы Rust?

1 ответ

Решение

Ты можешь использовать f32::from_bits а также to_bits безопасно переосмыслить необработанные кусочки u32 как f32и наоборот. Это "бесплатное" преобразование - оно не компилируется в код (с включенной оптимизацией). Для преобразования междуu32 а также i32 вы можете использовать as приведения, которые также бесплатны, когда используются для изменения подписи.

Мне кажется, что u32 является здесь общим знаменателем, так что вы можете подумать о том, чтобы struct который содержит u32 и предоставляет методы для получения или установки соответствующего типа:

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

Сравните сгенерированный код.

Смотрите также


¹ Эти функции используют transmuteвнутренне, который интерпретирует биты так же, как при использовании объединения. Поэтому, когда они встроены оптимизатором, сгенерированный код будет таким же.

Другие вопросы по тегам