回転シフト(ロタリー/サーキュラーシフト)操作は、特定のビット数だけ数のビットをシフトし、「流出」したビットを反対側に移動させることです。C言語にはこのタスク用の組み込み演算子がありません;このような解決策は、標準ライブラリの移植性と異なるプラットフォームに対する動作を明示的に定義する必要性に歴史的に関連しています。
問題は、標準的なシフト演算子(<<, >>)が回転シフトを行わず、ビットを単にシフトするだけで、「流出」したビットをゼロで置き換えることです。回転シフトでは、2つのシフトの結果を明示的に組み合わせ、指定されたビット数で結果をマスクする必要があります。
解決策は、手動で回転シフトを実装することです。32ビットのunsigned整数の場合は、次のようになります:
uint32_t rotate_left(uint32_t value, unsigned int shift) { return (value << shift) | (value >> (32 - shift)); } uint32_t rotate_right(uint32_t value, unsigned int shift) { return (value >> shift) | (value << (32 - shift)); }
主な特徴:
<< や >> 演算子で追加の操作なしに回転シフトを実装できますか?
いいえ。通常のシフトは、範囲外に出たビットをゼロで置き換え、他の側に移動させません。
データ型のサイズ(shiftが数のビット数に等しい)でシフトを行うとどうなりますか?
動作は未定義です(C標準による未定義動作)、型のサイズでモジュロシフトを必ず行う必要があります。
符号付き型に対して、これらの関数を使用してロタリーシフトを安全に行えますか?
いいえ、常にunsigned型を使用してください。符号付き型のビットシフトは、コンパイラやアーキテクチャによって異なる動作をするためです。
回転シフトのために通常のシフトを使用する:
uint32_t x = 0xFA3C0F00; uint32_t y = x << 5; // 回転的ではありません
利点:
欠点:
型のサイズを考慮し、未定義動作から保護するために手動のロタリーシフト関数を使用:
uint32_t x = 0xFA3C0F00; uint32_t y = rotate_left(x, 5);
利点:
欠点: