C#、およびVB(7.1以降)では、言語組み込みのシフト演算として、以下のシフト演算子が用意されています。 代入先を左オペランド(左項)とする複合代入演算子も用意されています。
シフト演算 | 演算子 | |
---|---|---|
C# | VB(7.1以降) | |
左シフト |
<< , <<= |
<< , <<= |
右シフト |
>> , >>= |
>> , >>= |
右シフト演算子は、左オペランド(左項・シフトされる値)が符号付き整数の場合は算術シフト(負数の場合は上位側ビットに1
、正数の場合は0
が補われる)となり、符号無し整数の場合は論理シフト(上位側ビットに常に0
が補われる)となります。 言い換えると、右シフト演算子では常に最上位ビット(符号ビット)と同じ値が補われます。 左シフト演算子では、常に0
が補われます。
右オペランド(右項・シフトする量、amount)は、常に左オペランドの型のビット数未満となるようにマスクされます。 例として32ビット整数をシフトしようとする場合、右オペランドの値は31(10)=11111(2)で自動的にマスク(AND演算)されます。 値が32ビット整数でシフト量が33の場合、33(10) AND 31(10) = 1(10)
つまりシフト量1のシフト演算となります。
このため、シフト量が型のビット数を超える値となる場合や、特に逆方向へのシフトを意図して負の値を指定してもそのとおりの動作とはならない点には注意が必要です。
右シフト・左シフト演算子では、型のビット数以上のシフト量はマスクされる
using System;
static class Sample {
static void Main()
{
int x = 1; // 32ビット整数
// 左右シフト演算子では、シフト量(amount)は常に型のビット数未満となるよう自動的にマスクされる
// 32ビット整数に対して33ビットシフトしようとすると、33 & (32 - 1) = 1ビットのシフトとなる
// 左シフト演算子の結果を2進数で表示
Console.WriteLine($"{x.ToBinary()} << 0 = {( x << 0 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} << 1 = {( x << 1 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} << 2 = {( x << 2 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} << 31 = {( x << 31 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} << 32 = {( x << 32 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} << 33 = {( x << 33 ).ToBinary()}");
Console.WriteLine();
x = int.MinValue;
// 右シフト演算子の結果を2進数で表示
Console.WriteLine($"{x.ToBinary()} >> 0 = {( x >> 0 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} >> 1 = {( x >> 1 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} >> 2 = {( x >> 2 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} >> 31 = {( x >> 31 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} >> 32 = {( x >> 32 ).ToBinary()}");
Console.WriteLine($"{x.ToBinary()} >> 33 = {( x >> 33 ).ToBinary()}");
Console.WriteLine();
}
#region "数値を二進数表記で文字列化するためのメソッド"
static string ToBinary(this int number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(int), '0');
#endregion
}
実行結果
0b_00000000000000000000000000000001 << 0 = 0b_00000000000000000000000000000001 0b_00000000000000000000000000000001 << 1 = 0b_00000000000000000000000000000010 0b_00000000000000000000000000000001 << 2 = 0b_00000000000000000000000000000100 0b_00000000000000000000000000000001 << 31 = 0b_10000000000000000000000000000000 0b_00000000000000000000000000000001 << 32 = 0b_00000000000000000000000000000001 0b_00000000000000000000000000000001 << 33 = 0b_00000000000000000000000000000010 0b_10000000000000000000000000000000 >> 0 = 0b_10000000000000000000000000000000 0b_10000000000000000000000000000000 >> 1 = 0b_11000000000000000000000000000000 0b_10000000000000000000000000000000 >> 2 = 0b_11100000000000000000000000000000 0b_10000000000000000000000000000000 >> 31 = 0b_11111111111111111111111111111111 0b_10000000000000000000000000000000 >> 32 = 0b_10000000000000000000000000000000 0b_10000000000000000000000000000000 >> 33 = 0b_11000000000000000000000000000000
回転シフト・循環シフトを行う場合はBitOperations.RotateLeftメソッド・RotateRightメソッドを使用します。 このメソッドでは、シフト量に負の値を指定すると逆方向への回転シフトとなります。