C# ビット演算の応用:特定のビット(フラグ)をON/OFFする方法

目次

ビット演算と「フラグ管理」

ビット演算は、数値を2進数のビット列として直接操作する技術です。この技術の強力な応用例の一つに「フラグ管理」があります。

フラグ管理とは、intbyteなどの一つの数値型変数の各ビット(0または1)を、それぞれ独立した「ON/OFF」や「Yes/No」の状態(フラグ)として割り当てて管理する手法です。これにより、複数のbool値を一つの数値変数にまとめて効率的に格納・操作できます。

この記事では、ビット演算の基本的なテクニックである「特定のNビット目をON(1に設定)する」方法と、「OFF(0に設定)する」方法について詳しく解説します。


準備:2進数表示ヘルパー

ビットの動きを視覚的に確認するため、16ビットの符号なし整数(ushort)を2進数文字列に変換するヘルパーメソッドを用意します。

using System;

public class BitFlagOperations
{
    /// <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)}";
    }

特定のビットをONにする (OR と 左シフト)

特定のビットをON(1)にするには、そのビット位置だけが1で、他がすべて0の「マスク」を作成し、元の数値と | (OR) 演算を行います。

ロジック:

  1. 1 << n を使って「Nビット目だけが1」のマスクを作成します。(nは0から数えます)
  2. 元の値 | マスク を計算します。| (OR) 演算は、どちらかが1なら1になるため、元のNビット目が0でも1でも、結果は必ず1(ON)になります。

コード例:ビットをONにする

0b_0000_0001_0010_0100 という値の「7ビット目」(0から数えて7番目)をONにしてみます。

    public static void Main()
    {
        ushort statusFlags = 0b_0000_0001_0010_0100; // (Decimal: 292)
        Console.WriteLine($"元の値 \t: {ToBinaryString(statusFlags)}");

        // --- 7ビット目をONにする ---
        int bitPositionOn = 7;

        // 1. マスクを作成 (1 を 7 ビット左にシフト)
        // マスク = 0b_0000_0000_1000_0000
        ushort maskOn = (ushort)(1 << bitPositionOn);
        Console.WriteLine($"ONマスク \t: {ToBinaryString(maskOn)} (第{bitPositionOn}ビット)");

        // 2. OR演算でフラグを立てる
        //   0000_0001_0010_0100 (元の値)
        // | 0000_0000_1000_0000 (マスク)
        // -------------------------
        //   0000_0001_1010_0100 (結果)
        ushort resultOn = (ushort)(statusFlags | maskOn);
        
        Console.WriteLine($"ON実行後 \t: {ToBinaryString(resultOn)}");
        Console.WriteLine("---");

出力結果:

元の値  : 0000_0001_0010_0100
ONマスク  : 0000_0000_1000_0000 (第7ビット)
ON実行後  : 0000_0001_1010_0100

7ビット目(右から8番目)が 0 から 1 に変わったことがわかります。


特定のビットをOFFにする (AND と NOT, 左シフト)

特定のビットをOFF(0)にするには、そのビット位置だけが0で、他がすべて1のマスクを作成し、元の数値と & (AND) 演算を行います。

ロジック:

  1. 1 << n を使って「Nビット目だけが1」のマスクを作成します。
  2. ~ (NOT) 演算子で、そのマスクの全ビットを反転させます。これにより「Nビット目だけが0で、他がすべて1」のOFF用マスクが完成します。
  3. 元の値 & マスク を計算します。& (AND) 演算は、両方1でないと0になるため、Nビット目は必ず0(OFF)になり、他のビットは元の値がそのまま維持されます。

コード例:ビットをOFFにする

0b_0000_0001_0010_0100 という値の「5ビット目」をOFFにしてみます。

        // --- 5ビット目をOFFにする ---
        ushort statusFlagsOff = 0b_0000_0001_0010_0100; // (Decimal: 292)
        Console.WriteLine($"元の値 \t: {ToBinaryString(statusFlagsOff)}");
        
        int bitPositionOff = 5;

        // 1. マスクを作成 (1 を 5 ビット左にシフト)
        // マスク = 0b_0000_0000_0010_0000
        ushort maskOffRaw = (ushort)(1 << bitPositionOff);

        // 2. ビット反転 (~) してOFF用マスクを作成
        // マスク = 0b_1111_1111_1101_1111
        ushort maskOff = (ushort)(~maskOffRaw);
        Console.WriteLine($"OFFマスク \t: {ToBinaryString(maskOff)} (第{bitPositionOff}ビット)");

        // 3. AND演算でフラグを降ろす
        //   0000_0001_0010_0100 (元の値)
        // & 1111_1111_1101_1111 (マスク)
        // -------------------------
        //   0000_0001_0000_0100 (結果)
        ushort resultOff = (ushort)(statusFlagsOff & maskOff);
        
        Console.WriteLine($"OFF実行後 \t: {ToBinaryString(resultOff)}");
    }
} // クラスの閉じ括弧

出力結果:

元の値  : 0000_0001_0010_0100
OFFマスク  : 1111_1111_1101_1111 (第5ビット)
OFF実行後  : 0000_0001_0000_0100

5ビット目(右から6番目)が 1 から 0 に変わったことがわかります。


まとめ

特定のNビット目を操作するテクニックは、ビット演算の基本であり、フラグ管理の核となります。

  • ビットをONにする: value = value | (1 << n);
    • | (OR) と、1をNビット左シフトしたマスクを使用します。
  • ビットをOFFにする: value = value & ~(1 << n);
    • & (AND) と、1をNビット左シフトしたマスクを ~ (NOT) で反転させたものを使用します。

この2つの操作を組み合わせることで、C#において複数の状態を効率的に管理できます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次