導入
ゲームのキャラクターが「毒」「スタン」「透明化」のような複数の状態を同時に持てるとき、状態ごとに 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) を定義し、state に FLAG_A だけを立てたうえで、FLAG_A が立っているか・FLAG_B が立っているかをそれぞれ判定して表示してください。
ヒント1を見る
state |= FLAG_A; で立てます。
ヒント2を見る
if (state & FLAG_A) printf("Aは立っています\n"); else printf("Aは立っていません\n"); のように調べます。FLAG_B も同様に調べます。