我发现我认为这是一种非常奇怪的行为.当变量在运行时溢出时,Rustc会发生混乱; 这对我来说很有意义.但是,它只会在编译时分配溢出值时发出警告.那应该是编译时错误吗?否则,两种行为似乎不一致.
我期待编译时错误:
fn main() {
let b: i32 = 3_000_000_000;
println!("{}", b);
}
Run Code Online (Sandbox Code Playgroud)
生产:
<anon>:2:18: 2:31 warning: literal out of range for i32, #[warn(overflowing_literals)] on by default
<anon>:2 let b: i32 = 3_000_000_000;
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义:
fn main() {
let b: i32 = 30_000;
let c: i32 = 100_000;
let d = b * c;
println!("{}", d);
}
Run Code Online (Sandbox Code Playgroud)
生产:
thread '<main>' panicked at 'arithmetic operation overflowed', <anon>:4
playpen: application terminated with error code 101
Run Code Online (Sandbox Code Playgroud)
编辑:
鉴于FrancisGagné的评论,我发现Rust实现了在操作期间检查溢出的运算符,例如checked_mul,我发现需要自己实现溢出检查.这是有道理的,因为应该优化发布版本,并且不断检查溢出可能会变得昂贵.所以我不再看到"不一致".但是,我仍然感到惊讶,分配一个溢出的值不会导致编译时错误.在golang它会:去游乐场
实际上,您的评论与您观察到的行为并不相符:
Go 示例与第一个 Rust 示例类似(除了 Go 在设计上没有警告)。
在 Rust 中,下溢或上溢会导致未指定的值,这在计算机科学中可以是!或底部,这是一个特殊的值,表示控制流发散,通常意味着中止或异常。
该规范允许:
并且两种模式都符合规范。
1 默认情况下不进行检测,如果您选择的话,您可以在繁重的数字代码之外以相对适中的性能成本激活发布中的溢出检查,并使用一个简单的标志。
关于溢出检查的成本:目前的 Rust/LLVM 情况对调试有帮助,但还没有真正优化。因此,在这个框架中,溢出检查成本。如果情况有所改善,那么有一天,rustc 可能会决定默认激活溢出检查,即使在发布版本中也是如此。
在Midori(用类似于 C# 的语言开发的 Microsoft 实验操作系统)中,即使在 Release 版本中也打开了溢出检查:
在 Midori 中,我们默认启用溢出检查进行编译。这与普通 C# 不同,在 C# 中,您必须显式传递 /checked 标志才能实现此行为。根据我们的经验,发现的意外溢出数量所带来的不便和成本是值得的。但这确实意味着我们的编译器需要真正善于理解如何消除不必要的。
显然,他们改进了编译器,以便:
后者只能在发布中完成(您会失去精度),但会减少分支数量。
那么,还剩下什么成本呢?
可能妨碍优化的不同算术规则:
64 + x - 128可以优化为x - 64;激活溢出检查后,编译器可能无法执行此优化不过,除非代码大量数字化(例如科学模拟或图形),否则它确实可能会产生影响。