LoginSignup
21
15

More than 5 years have passed since last update.

Rustで算術オーバーフローを無視する

Last updated at Posted at 2016-05-18

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 :clap:)

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::Wrappingwrapping_* を使う方が無難そうです。

また現時点で cargo 経由でビルドする際に rustc のコンパイルオプションを指定する方法は無いみたいなので、 cargo を使う場合もこのアプローチを採用することはできません。

参考文献

21
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
15