Выполняет ли Rust приведение типов во время выполнения или при компиляции статически?

Играя с C или другими языками программирования, я всегда сталкиваюсь с ситуацией, когда невозможно избежать приведения типов, например. let c_var = rust_var as u32, и я чувствую, что волнуюсь за выступление.

Выполняется ли приведение типов во время выполнения или компиляции? Использование встроенного as не так эффективно?

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Выполняется ли приведение типов во время выполнения или компиляции? Является ли использование в качестве встроенного не таким эффективным?

Обычно зависит от того, есть ли изменение представления. Если есть, то в актерском составе обязательно есть компонент времени выполнения, например. целое число -> целое число, целое число -> число с плавающей запятой, число с плавающей запятой -> целое число.

Однако эти преобразования обычно являются аппаратными операциями, возможно, даже аппаратными без операций, например. если вы конвертируете u16 в u32, на x64 компилятор просто сохранит u16 и прочитает u32 из того же регистра, возможно, используя mov-with-zero-extend (зависит от семантики регистров).

Если вы беспокоитесь, вы можете просто посмотреть, что выдает Godbolt, чтобы получить подсказки или доказательства. Например:

pub fn conv(num: u16) -> u32 {
    num as _
}

pub fn conv2(num: u32) -> u64 {
    num as _
}
example::conv:
        movzx   eax, di
        ret

example::conv2:
        mov     eax, edi
        ret

потому что на x86 16-битные (и 8-битные) регистры не расширяются до нуля, а 32-битные регистры:

  • 32-битные операнды генерируют 32-битный результат, расширенный от нуля до 64-битного результата в целевом регистре общего назначения.
  • 8-битные и 16-битные операнды генерируют 8-битный или 16-битный результат. Старшие 56 бит или 48 бит (соответственно) целевого регистра общего назначения не изменяются операцией. Если результат 8-битной или 16-битной операции предназначен для вычисления 64-битного адреса, явно расширьте регистр по знаку до полных 64-бит.

Таким образом, если данные «поступают» правильно, приведение не выполняется во время выполнения, несмотря на то, что оно происходит во время выполнения (поскольку оно соответствует поведению ISA по умолчанию). Если это не так, может потребоваться выполнение явной операции, например. u16 -> u32 на ARM64 требует явного обнуления старших 16 бит:

example::conv:
        and     w0, w0, #0xffff
        ret

потому что ARM с самого начала была архитектурой 32b, однако это не проблема для u32 -> u64:

example::conv2:
        mov     w0, w0
        ret

потому что в отличие от x86 он расширяется нулями.

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