本文へスキップ
BecomeCoder

C言語コース · 第12章 ビット操作 · レッスン47

ビットフラグとビットマスク ― 複数のON/OFFを1つの整数にまとめる

ブラウザで完結

導入

ゲームのキャラクターが「毒」「スタン」「透明化」のような複数の状態を同時に持てるとき、状態ごとに int 変数を作るのではなく、1つの整数の各ビットを1つずつの状態(フラグ)として使うと、省メモリかつ高速に管理できます。

説明

まず、それぞれのフラグが「何ビット目か」を #define で定義するのが定石です。1 << n で「右から n+1 番目のビットだけが1」の値を作れます(例: #define FLAG_POISON (1 << 0) なら 0001#define FLAG_STUN (1 << 1) なら 0010)。

このように定義したフラグは、次の4つの操作で扱います。

  • 立てる(ONにする): state |= FLAG_POISON;
  • 消す(OFFにする): state &= ~FLAG_POISON;
  • 立っているか調べる: if (state & FLAG_POISON) { ... }
  • 反転する(トグル): state ^= FLAG_POISON;
flowchart LR
  subgraph state["state(1つの整数の中のビット)"]
    direction LR
    b2["bit2: invisible"]
    b1["bit1: stun"]
    b0["bit0: poison"]
  end
#include <stdio.h>

#define FLAG_POISON    (1 << 0)
#define FLAG_STUN      (1 << 1)
#define FLAG_INVISIBLE (1 << 2)

int main(void) {
    unsigned int state = 0;

    state |= FLAG_POISON;
    state |= FLAG_STUN;
    printf("状態の値: %u\n", state);

    if (state & FLAG_POISON) {
        printf("毒状態です\n");
    }
    if (state & FLAG_INVISIBLE) {
        printf("透明状態です\n");
    } else {
        printf("透明ではありません\n");
    }

    state &= ~FLAG_POISON;
    printf("毒を治療しました\n");
    if (state & FLAG_POISON) {
        printf("まだ毒です\n");
    } else {
        printf("毒は治りました\n");
    }

    return 0;
}

state &= ~FLAG_POISON; の部分は、「FLAG_POISON のビットだけを反転させたマスク(他のビットは全部1)」と AND を取ることで、「そのビットだけを0にし、他のビットはそのまま残す」という意味になります。

やってみよう

FLAG_INVISIBLE も立ててみましょう。state ^= FLAG_STUN; を追加して、スタン状態をトグル(今と反対の状態に切り替え)してみてください。もう一度実行すると元に戻ることも確認してみましょう。

演習

#define FLAG_A (1 << 0)#define FLAG_B (1 << 1) を定義し、stateFLAG_A だけを立てたうえで、FLAG_A が立っているか・FLAG_B が立っているかをそれぞれ判定して表示してください。

ヒント1を見る

state |= FLAG_A; で立てます。

ヒント2を見る

if (state & FLAG_A) printf("Aは立っています\n"); else printf("Aは立っていません\n"); のように調べます。FLAG_B も同様に調べます。

実際に動かしてみよう

下のエディタにCを書いて「実行」を押すと、ブラウザ内のインタプリタで出力が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう(scanf を使う回は「標準入力」欄に値を入れてから実行します)。

C/C++ — ブラウザ内で実行

ブラウザ内でC/C++を動かす学習用インタプリタ(JSCPP)を読み込みます(入門向けのサブセットです)。
スクロールして表示された時点でも自動で読み込まれます。