Rustで算術オーバーフローが起こるとエラーが発生します。例えば
let a = 0xff as u8;
let b = 0x01 as u8;
println!("0x{:02x} + 0x{:02x} = 0x{:02x}", a, b, a + b);
を実行すると
panicked at 'arithmetic operation overflowed'
といってプログラムが終了します。基本的には嬉しい機能ですが、これを無視したい場合は3通りの対応方法があります。
std::num::Wrapping
最初の方法は std::num::Wrapping を使う方法です。
use std::num::Wrapping;
let a = 0xff as u8;
let b = 0x01 as u8;
println!("0x{:02x} + 0x{:02x} = 0x{:02x}", a, b, (Wrapping(a) + Wrapping(b)).0);
これを実行すると
0xff + 0x01 = 0x00
と標準出力に書きだされます。ちなみに .0
の部分は Wrapping
struct 内の u8
にアクセスするために必要なやつです。
wrapping_* メソッドを使う
プリミティブな数値型に定義された wrapping_*
メソッドを使うことができます。(Thanks for @tatsuya6502 )
let a = 0xff as u8;
let b = 0x01 as u8;
println!("0x{:02x} + 0x{:02x} = 0x{:02x}", a, b, a.wrapping_add(b));
このメソッドは内部的に std::num::Wrapping
を使っています。
-Z force-overflow-checks=off
もう一つの方法は rustc
のコンパイルオプションに -Z force-overflow-checks=off
を渡すことです。これにより算術オーバーフローが発生してもエラーにならなくなります。
しかし、この方法は算術オーバーフローを無視するというよりは、算術オーバーフローが発生しないことが分かっている時に、パフォーマンス最適化のために指定するもののようです。
また、将来に渡ってこのオプションが提供されるのか、提供されるとして同じような意味を持ち続けるのかは不透明なので、先ほどの std::num::Wrapping
や wrapping_*
を使う方が無難そうです。
また現時点で cargo
経由でビルドする際に rustc
のコンパイルオプションを指定する方法は無いみたいなので、 cargo
を使う場合もこのアプローチを採用することはできません。