Integer operations
Integer overflows
Although Rust performs some checks for potential integer overflows, precautions should be taken when executing arithmetic operations on integers.
In particular, note that the compilation profile (typically dev, the default debug build, or release, the standard optimized build) changes integer overflow behavior. In the dev configuration, overflow causes the termination of the program (panic), whereas in the release configuration, the computed value is silently truncated to the number of bits of the numeric type, giving it wrap-around semantics.
The integer overflow behavior can be explicitly defined by the compilation option -C overflow-checks=true (or false).
It can also be modified in the profile definition in Cargo.toml:
[profile.release]
overflow-checks = true # enable overflow checks in release builds
When an overflow is possible, the behavior can be made explicit either by using specific methods or by using specific wrapper types.
The methods are of the form <mode>_<op>, where <mode> is checked, overflowing, wrapping, or saturating, and <op> is add, mul, sub, shr, etc. The semantics are as follows:
checked_<op>returnsNonein case of overflow,overflowing_<op>returns both a possibly wrapped result and a Boolean indicating whether overflow occurred,wrapping_<op>always returns the wrapped result,saturating_<op>always returns the saturated result.
The wrapper types are Wrapping<T> and Saturating<T> (from std::num), where T is an integer type. The former provides wrap-around semantics for all arithmetic operations, whereas the latter provides saturation semantics. Once the values are wrapped, all subsequent operations are performed with the given semantics.
#![allow(unused)] #![allow(dead_code)] fn main() { use std::num::Wrapping; use std::panic; fn use_integer() { let x: u8 = 242; let result = panic::catch_unwind(|| { println!("{}", x + 50); // panics in debug, prints 36 in release. }); if result.is_err() { println!("panic"); } // always prints 36. println!("{}", x.overflowing_add(50).0); // always prints 36. println!("{}", x.wrapping_add(50)); // always prints 36. println!("{}", Wrapping(x) + Wrapping(50)); // always panics: let (res, c) = x.overflowing_add(50); let result = panic::catch_unwind(|| { if c { panic!("custom error"); } else { println!("{}", res); } }); if result.is_err() { println!("panic"); } } }
When an arithmetic operation can produce an overflow, the usual operators MUST NOT be used directly.
Instead, specialized methods such as checked_<op>, overflowing_<op>, wrapping_<op>, or saturating_<op>, or specialized wrapper types like Wrapping or Saturating, MUST be used to ensure explicit and consistent behavior regardless of the compilation profile.