测试溢出时忽略 Cargo build --release 选项

问题描述

我一直在逐步阅读《编程 Rust》这本书,想观察两个补码包装,代码很简单:

fn main() {

    let mut x: u8 = 255;
    println!("the value of x is {}",x) ;
    x = 255 + 1 ;
    println!("The value of x Now is {}",x) ;
}

当我按照指南尝试使用 Cargo 编译它时,我运行 货物构建--发布 书中说将让它在没有溢出保护的情况下编译,但它不会编译。我收到保护错误

| 6 | x = 255 + 1 ;

| ^^^^^^^^^^^^ 尝试计算u8::MAX + 1_u8,这会溢出

你能解释一下我做错了什么吗?

解决方法

我相信在运行时不会动态检查该值(它不会 panic 并且会溢出),但在编译时仍会静态检查(如果可能)。

在这种情况下,编译器能够在编译时确定您要执行的操作并阻止您执行此操作。

也就是说,如果您查看编译器输出,您可以看到以下消息:

注意:#[deny(arithmetic_overflow)] 默认开启

无论优化级别如何,您都会看到此消息。

如果您想观察溢出,请将以下 inner attribute 放在源文件的顶部。

#![allow(arithmetic_overflow)]

或者,如果您直接使用 rustc 进行编译,则可以传递以下标志:

-O -A arithmetic_overflow

rustc 文档显示以下 lint 默认处于启用状态(无论优化级别如何)

  • ambiguous_related_items
  • arithmetic_overflow
  • conflicting_repr_hints
  • const_err
  • ill_formed_attribute_input
  • incomplete_include
  • invalid_type_param_default
  • macro_expanded_macro_exports_accessed_by_absolute_paths
  • missing_fragment_specifier
  • mutable_transmutes
  • no_mangle_const_items
  • order_dependent_trait_objects
  • overflowing_literals
  • patterns_in_fns_without_body
  • pub_use_of_private_extern_crate
  • soft_unstable
  • unconditional_panic
  • unknown_crate_types
  • useless_deprecated
,

当您在代码中编写 literal 255+1 时,编译器会在编译时评估表达式并立即看到溢出,无论是在调试模式还是发布模式。当书中说 --release 禁用溢出保护时,它指的是运行时检查。你可以看到这段代码的不同之处:

fn increment (x: u8) -> u8 { x + 1 }

fn main() {
    let x = 255;
    println!("x: {},x+1: {}",x,increment (x));
}

Playground

如果您在调试模式下运行此代码,您将得到:

thread 'main' panicked at 'attempt to add with overflow',src/main.rs:1:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

但是如果你在发布模式下运行它,你会得到:

x: 255,x+1: 0