ビットフラグの状態判定
C#でビット演算を用いて複数の状態(フラグ)を一つの数値変数で管理する際、「特定のビットをON/OFFする」操作と並んで重要なのが、「特定のビットが現在ON(1)なのか、OFF(0)なのかを判定する」操作です。
例えば、「読み取り許可」フラグ(例: 3ビット目)が立っているかどうかをbool値として取得したい場合などに、このテクニックが使用されます。
この記事では、ビット演算の&(AND)と<<(左シフト)を組み合わせた、特定のビットの状態を判定する標準的な方法を解説します。
準備:2進数表示ヘルパー
ビットの状態を視覚的に確認するため、16ビットの符号なし整数(ushort)を2進数文字列に変換するヘルパーメソッドを用意します。
using System;
public class BitCheckExample
{
/// <summary>
/// 16ビット符号なし整数(ushort)を、0埋めした2進数文字列に変換します。
/// </summary>
static string ToBinaryString(ushort value)
{
// 16桁の2進数文字列(例: "0000_0001_0010_0100")として整形
string binary = Convert.ToString(value, 2).PadLeft(16, '0');
return $"{binary.Substring(0, 4)}_{binary.Substring(4, 4)}_{binary.Substring(8, 4)}_{binary.Substring(12, 4)}";
}
Nビット目の状態を判定するロジック
特定のNビット目がON(1)かどうかを判定するには、以下の3ステップのロジックを使用します。
- マスクの作成:
1 << nを使用し、判定したいNビット目(0から数える)だけが1で、他がすべて0の「マスク」を作成します。 &(AND) 演算の適用: 判定したい元の値と、作成したマスクで&(AND) 演算を行います。- 結果の判定:
- もし元の値のNビット目が
0だった場合、0 & 1は0になります。マスクの他のビットはすべて0なので、&演算の結果は全体として0になります。 - もし元の値のNビット目が
1だった場合、1 & 1は1になります。&演算の結果は、マスクと**同じ値(0ではない)**になります。
- もし元の値のNビット目が
したがって、&演算の結果が0でなければ(!= 0)、Nビット目はON(1)であったと判定できます。
判定式: (value & (1 << n)) != 0
コード例:ビットの状態判定
0b_0000_0101_0011_0000 という値について、ONになっているビット(例: 8ビット目)と、OFFになっているビット(例: 3ビット目)をそれぞれ判定してみます。
public static void Main()
{
// 判定対象の値 (8ビット目, 9ビット目, 10ビット目がON)
ushort permissionFlags = 0b_0000_0101_0011_0000; // (Decimal: 1328)
Console.WriteLine($"判定対象の値: {ToBinaryString(permissionFlags)}");
Console.WriteLine("---");
// --- 例1: ONになっているビットの判定 (8ビット目) ---
int bitPositionOn = 8;
// 1. マスクを作成 (1 << 8) = 0b_0000_0001_0000_0000
ushort maskOn = (ushort)(1 << bitPositionOn);
Console.WriteLine($"判定マスク(8): {ToBinaryString(maskOn)}");
// 2. AND演算
// 0000_0101_0011_0000 (元の値)
// & 0000_0001_0000_0000 (マスク)
// -------------------------
// 0000_0001_0000_0000 (結果: 0ではない)
ushort resultOn = (ushort)(permissionFlags & maskOn);
Console.WriteLine($"AND演算結果: {ToBinaryString(resultOn)}");
// 3. 結果の判定 (0ではないか?)
bool isBitOn = (resultOn != 0);
Console.WriteLine($"第{bitPositionOn}ビットはONか: {isBitOn} (True)");
Console.WriteLine("---");
// --- 例2: OFFになっているビットの判定 (3ビット目) ---
int bitPositionOff = 3;
// 1. マスクを作成 (1 << 3) = 0b_0000_0000_0000_1000
ushort maskOff = (ushort)(1 << bitPositionOff);
Console.WriteLine($"判定マスク(3): {ToBinaryString(maskOff)}");
// 2. AND演算
// 0000_0101_0011_0000 (元の値)
// & 0000_0000_0000_1000 (マスク)
// -------------------------
// 0000_0000_0000_0000 (結果: 0である)
ushort resultOff = (ushort)(permissionFlags & maskOff);
Console.WriteLine($"AND演算結果: {ToBinaryString(resultOff)}");
// 3. 結果の判定 (0ではないか?)
bool isBitOff = (resultOff != 0);
Console.WriteLine($"第{bitPositionOff}ビットはONか: {isBitOff} (False)");
}
} // クラスの閉じ括弧
出力結果:
判定対象の値: 0000_0101_0011_0000
---
判定マスク(8): 0000_0001_0000_0000
AND演算結果: 0000_0001_0000_0000
第8ビットはONか: True (True)
---
判定マスク(3): 0000_0000_0000_1000
AND演算結果: 0000_0000_0000_0000
第3ビットはONか: False (False)
まとめ
特定のNビット目がON(1)かどうかを判定するC#の標準的なイディオムは、&(AND)演算子を用いて0と比較することです。
bool isBitOn = (value & (1 << n)) != 0;
この式は、valueのNビット目だけを抽出し、その結果が0ではない(=ビットが立っていた)場合にtrueを返します。これは、ビットフラグの読み取りにおいて非常に高速で効率的な操作です。
