Ale*_*vik 8 integer-overflow rust rust-cargo
我有这段简单的代码:
let val: u8 = 255 + 1;
println!("{}", val);
Run Code Online (Sandbox Code Playgroud)
这里据说这样的代码如果使用--releaseflag运行的话会正常编译。
我通过 运行此代码cargo run --release,并且仍然看到检查:
error: this arithmetic operation will overflow
--> src/main.rs:2:19
|
2 | let val: u8 = 255 + 1;
| ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
error: could not compile `rust-bin` due to previous error
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
use*_*342 15
书上说得有点不严谨。调试和发布模式下都不允许溢出,只是发布模式出于性能原因省略了运行时检查(用溢出代替它们,CPU 通常都会这样做)。静态检查不会被删除,因为它们不会影响生成代码的性能。这在发布模式下打印 0 并在调试1下出现恐慌:
let x: u8 = "255".parse().unwrap();
let val: u8 = x + 1;
println!("{}", val);
Run Code Online (Sandbox Code Playgroud)
您可以使用 禁用编译时检查#[allow(arithmetic_overflow)]。这也会在发布模式下打印 0 并在调试模式下出现恐慌:
#[allow(arithmetic_overflow)]
let val: u8 = 255 + 1;
println!("{}", val);
Run Code Online (Sandbox Code Playgroud)
正确的做法是不依赖于发布模式的这种行为,而是告诉编译器你想要什么。在调试和发布模式下都会打印 0:
let val: u8 = 255u8.wrapping_add(1);
println!("{}", val);
Run Code Online (Sandbox Code Playgroud)
1
该示例使用的"255".parse()原因是,令我惊讶的是,它let x = 255u8; let val = x + 1; 无法编译- 换句话说,rustc 不仅可以防止常量算术中的溢出,而且还可以在其他任何可以证明溢出发生的地方。该更改显然是在 Rust 1.45 中进行的,因为它是在Rust 1.44 及更早版本中编译的。由于它破坏了之前编译的代码,因此该更改在技术上是向后不兼容的,但大概破坏了足够少的实际板条箱,因此被认为是值得的。令人惊讶的是,这很可能会"255".parse::<u8>() + 1在以后的版本中成为编译时错误。