为什么 Rust 在 --release 中执行整数溢出检查?
Why does Rust perform integer overflow checks in --release?
我有这段简单的代码:
let val: u8 = 255 + 1;
println!("{}", val);
据说here如果运行带有--release
标志,这样的代码将正常编译。
我通过 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
我是不是漏掉了什么?
这本书有点不严谨。在调试和发布模式下都不允许溢出,只是发布模式出于性能原因省略了 runtime 检查(用溢出代替它们,CPU 通常会这样做)。静态检查不会被删除,因为它们不会影响生成代码的性能。这在发布模式下打印 0 并在 debug1:
中出现恐慌
let x: u8 = "255".parse().unwrap();
let val: u8 = x + 1;
println!("{}", val);
您可以使用 #[allow(arithmetic_overflow)]
禁用编译时检查。这也会在发布模式下打印 0 并在调试时出现恐慌:
#[allow(arithmetic_overflow)]
let val: u8 = 255 + 1;
println!("{}", val);
正确的做法是不依赖于发布模式的这种行为,而是告诉编译器你想要什么。这在调试和发布模式下都打印 0:
let val: u8 = 255u8.wrapping_add(1);
println!("{}", val);
1
该示例使用 "255".parse()
,因为令我惊讶的是 let x = 255u8; let val = x + 1;
doesn't compile - in other words, rustc doesn't just prevent overflow in constant arithmetic, but also wherever else it can prove it happens. The change was apparently made in Rust 1.45, because it compiled in Rust 1.44 and older。由于它破坏了先前编译的代码,因此该更改在技术上是不向后兼容的,但大概破坏了足够少的实际板条箱,因此被认为是值得的。令人惊讶的是,"255".parse::<u8>() + 1
很可能会在以后的版本中成为编译时错误。
在您的代码中,编译器能够检测到问题。这就是为什么即使在发布模式下它也会阻止它。在许多情况下,编译器检测或防止错误是不可能或不可行的。
举个例子,假设您有这样的代码:
let a = b + 5;
假设 b
的值来自数据库、用户输入或其他一些外部来源。在这种情况下要防止溢出实际上是不可能的。
我有这段简单的代码:
let val: u8 = 255 + 1;
println!("{}", val);
据说here如果运行带有--release
标志,这样的代码将正常编译。
我通过 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
我是不是漏掉了什么?
这本书有点不严谨。在调试和发布模式下都不允许溢出,只是发布模式出于性能原因省略了 runtime 检查(用溢出代替它们,CPU 通常会这样做)。静态检查不会被删除,因为它们不会影响生成代码的性能。这在发布模式下打印 0 并在 debug1:
中出现恐慌let x: u8 = "255".parse().unwrap();
let val: u8 = x + 1;
println!("{}", val);
您可以使用 #[allow(arithmetic_overflow)]
禁用编译时检查。这也会在发布模式下打印 0 并在调试时出现恐慌:
#[allow(arithmetic_overflow)]
let val: u8 = 255 + 1;
println!("{}", val);
正确的做法是不依赖于发布模式的这种行为,而是告诉编译器你想要什么。这在调试和发布模式下都打印 0:
let val: u8 = 255u8.wrapping_add(1);
println!("{}", val);
1
该示例使用 "255".parse()
,因为令我惊讶的是 let x = 255u8; let val = x + 1;
doesn't compile - in other words, rustc doesn't just prevent overflow in constant arithmetic, but also wherever else it can prove it happens. The change was apparently made in Rust 1.45, because it compiled in Rust 1.44 and older。由于它破坏了先前编译的代码,因此该更改在技术上是不向后兼容的,但大概破坏了足够少的实际板条箱,因此被认为是值得的。令人惊讶的是,"255".parse::<u8>() + 1
很可能会在以后的版本中成为编译时错误。
在您的代码中,编译器能够检测到问题。这就是为什么即使在发布模式下它也会阻止它。在许多情况下,编译器检测或防止错误是不可能或不可行的。
举个例子,假设您有这样的代码:
let a = b + 5;
假设 b
的值来自数据库、用户输入或其他一些外部来源。在这种情况下要防止溢出实际上是不可能的。