【小测试】rust中的无符号整数溢出
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
1.在编译阶段就可以识别出来的溢出
fn main(){
let a : usize = 1;
println!("{}",a-2);
}
执行rustc报以下错误:
rustc usize_test.rs
error: this arithmetic operation will overflow
--> usize_test.rs:4:19
|
4 | println!("{}",a-2);
| ^^^ attempt to compute `1_usize - 2_usize`, which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
error: aborting due to previous error
2.运行期溢出
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let start = SystemTime::now();
let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let ts = since_the_epoch.as_secs() as usize;
//
let a:usize = 1;
let b :usize= ts % 10 + 2;
println!("a={:?}, b={:?}", a,b);
//
println!("{:?}", a-b);
}
当溢出发生的时候,程序panic了:
thread 'main' panicked at 'attempt to subtract with overflow', usize_test_3.rs:16:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
由此也说明,rust不是真正的零成本抽象。为了防止无符号整形的溢出,必然需要在减法之前编译进去一个范围判断。
3.如何才能做溢出不panic的减法
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let start = SystemTime::now();
let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let ts = since_the_epoch.as_secs() as usize;
//
let a:usize = 1;
let b :usize= ts % 10 + 2;
println!("a={:?}, b={:?}", a,b);
//
println!("{:?}", a.wrapping_sub(b));
}
使用wrapping_sub()这个方法。
rust是如此的严谨,情愿使用的时候很啰嗦,也不要在运行时挖坑。
4. 通过release版本跳过溢出检查
在新的目录,执行:cargo new usize_test
在上面的代码写在:usize_test/src/main.rs 中
在usize_test目录执行:cargo build --release
然后执行 usize_test/target/release/usize_test,发现usize类型的溢出已经不会panic了,其结果与执行 wrapping_sub() 一样。
(感谢zhihu网友 @QDelta 提醒。)
不过我又陷入了迷惑:
- 既然release版本就不检查usize溢出了,还要wrapping_sub()这样的方法干啥?
- 对于溢出这样的情况,应该有程序员通过不同的写法来决定如何处理。如果编译个release版本就能跳过,rust又和C/C++有啥区别?