fn main() {
    let num: u8 = 255;
    let num2: u8 = num + 1;
    println!("{}, {}", num, num2);
}

值为$ cargo build --release时,此代码不会出现编译错误. $ cargo run、制造运行时错误.

线程‘main’在‘try 添加时溢出’时死机,src/main.rs:3:20 注意:使用RUST_BACKTRACE=1环境变量运行可显示回溯

这样就可以了.但我不明白的是下面的情况. 当我删除println行时,会出现编译错误.

fn main() {
    let num: u8 = 255;
    let num2: u8 = num + 1;
}
$ cargo build --release

error: this arithmetic operation will overflow
 --> src/main.rs:3:20
  |
3 |     let num2: u8 = num + 1;
  |                    ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default

为什么整数溢出有时会导致编译错误或运行时错误?

推荐答案

当编译器可以很容易地证明它会在运行时溢出时,这将是一个编译时错误,当你删除println时就会发生这种情况,因为num可以很容易地内联(反正它只在那个位置使用),但是println很难优化,因为它引用了它的参数,而且很难证明不同的地址不会对它产生影响(考虑还有一个fmt::Pointer)所有这些都导致了一个事实,对于第一种情况,num不能那么容易内联,证明它不是那么微不足道.

以下是每个变量中第一个和第二个变量的mir表示,您可以看到其中一个变量已经被替换为u8::MAX:

  • 如果没有println:
    [...]
        bb0: {
            _1 = const u8::MAX;              // scope 0 at plain_overflow.rs:2:19: 2:22
            _3 = const u8::MAX;              // scope 1 at plain_overflow.rs:3:20: 3:23
            _4 = CheckedAdd(_3, const 1_u8); // scope 1 at plain_overflow.rs:3:20: 3:27
            assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", move _3, const 1_u8) -> bb1; // scope 1 at main.rs:3:20: 3:27
        }
    [...]
    
  • 使用println:
    [...]
        bb0: {
            _1 = const u8::MAX;              // scope 0 at with_print.rs:2:19: 2:22
            _3 = _1;                         // scope 1 at with_print.rs:3:20: 3:23
            _4 = CheckedAdd(_3, const 1_u8); // scope 1 at with_print.rs:3:20: 3:27
            assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", move _3, const 1_u8) -> bb1; // scope 1 at with_print.rs:3:20: 3:27
        }
    [...]
    

其中,在这两种情况下,_1_3_4都对应于num,即赋值为num2的行中的值num以及分别为num1的判断加法的结果.

经过更多的试验,罪魁祸首不是println,而仅仅是taking a reference to num

Rust相关问答推荐

使用nom将任何空白、制表符、白线等序列替换为单个空白

为什么幻影数据不能自动推断?

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

在跨平台应用程序中使用std::OS::Linux和std::OS::Windows

使用铁 rust S还原对多个数组执行顺序kronecker积

是否可以使用Rust宏来构建元组的项?

RUST应用程序正在退出,错误代码为:(退出代码:0xc0000005,STATUS_ACCESS_VIOLATION)

正在将带有盒的异步特征迁移到新的异步_fn_in_特征功能

如何强制匹配的返回类型为()?

Rust 如何返回大类型(优化前)?

如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

如何从 rust 中的同一父目录导入文件

有没有办法隐式绑定 let/match 操作的成员?

按下 Ctrl + C 时优雅地停止命令并退出进程

如果不满足条件,如何在 Rust 中引发错误

我什么时候应该使用特征作为 Rust 的类型?

仅在运行测试时生成调试输出

If let expression within .iter().any

Rust - 在线程之间不安全地共享没有互斥量的可变数据

通用类型,不同于输入类型,作为函数的返回值