Jun*_*hee 20 integer-overflow rust
fn main() {
let num: u8 = 255;
let num2: u8 = num + 1;
println!("{}, {}", num, num2);
}
Run Code Online (Sandbox Code Playgroud)
当 时$ cargo build --release,这段代码不会产生编译错误。并且$ cargo run,产生运行时错误。
线程“main”因“尝试添加溢出”而惊慌失措,src/main.rs:3:20 注意:使用
RUST_BACKTRACE=1环境变量运行以显示回溯
这没关系。但我不明白的是下面的情况。当我删除 println 行时,会出现编译错误。
fn main() {
let num: u8 = 255;
let num2: u8 = num + 1;
}
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
为什么整数溢出有时会导致编译错误或运行时错误?
当编译器可以简单地证明它会在运行时溢出时,这将是一个编译时错误,当您删除时会发生这种情况,println因为 thennum可以轻松内联(无论如何它只在那个地方使用),但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
}
[...]
Run Code Online (Sandbox Code Playgroud)
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
}
[...]
Run Code Online (Sandbox Code Playgroud)
其中,在这两种情况下_1,_3和_4分别对应于、行中被分配num的值以及和的检查加法的结果。numnum2num1
经过更多的实验后,println罪魁祸首并不是,而只是参考num