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