Q: Так что, если компиляторы Rust выполняют ту же самую оптимизацию, что и компиляторы C / C ++ в отношении целых чисел со знаком
Rust - нет. Поскольку, как вы заметили, он не может выполнить эту оптимизацию, поскольку целочисленные переполнения хорошо определены.
Для добавления в режим выпуска Rust выдаст следующую инструкцию LLVM (вы можете проверить на игровой площадке ):
add i32 %b, %a
С другой стороны, clang выдаст следующую инструкцию LLVM (вы можете проверить через clang -S -emit-llvm add.c
):
add nsw i32 %6, %8
Разница составляет nsw
( без подписи). Как указано в ссылке LLVM о add
:
Если сумма имеет переполнение без знака, возвращаемый результат является математическим результатом по модулю 2n, где n - ширина бита результат.
Поскольку целые числа LLVM используют представление в виде дополнения до двух, эта инструкция подходит для целых чисел как со знаком, так и без знака. «Без подписи», соответственно. Если присутствуют ключевые слова nuw
и / или nsw
, результирующее значение дополнения является ошибочным значением, если происходит переполнение без знака и / или со знаком, соответственно.
Значение яда что приводит к неопределенному поведению. Если флаги отсутствуют, результат хорошо определяется как перенос дополнения 2.
Q: Или даже если компиляторы Rust не выполняют такую оптимизацию, программисты Rust все еще не ожидайте увидеть подписанное целое число, оборачивающееся вокруг. Разве это не может быть названо «неопределенным поведением»?
«Неопределенное поведение», как используется в этом контексте, имеет очень специфическое c значение, которое отличается от интуитивного значения Engli sh два слова. В частности, UB здесь означает, что компилятор может предполагать, что переполнение никогда не произойдет, и что , если произойдет переполнение, любое поведение программы разрешено. Это не то, что указывает Rust.
Однако целочисленное переполнение с помощью арифметических c операторов считается ошибкой в Rust. Это потому, что, как вы сказали, это обычно не ожидается. Если вы намеренно хотите использовать режим обтекания, есть такие методы, как i32::wrapping_add
.
Некоторые дополнительные ресурсы: