ファミコン時代のゲームプログラミングでは、メモリが極端に少なかったため、キャラクターの状態(無敵、ジャンプ中、被弾中など)を1バイトの中に複数のビットフラグとして詰め込むのが定石だった。今日のインディーゲーム開発でもこの発想は生きていて、ビット演算は理論だけでなく実務でも現役の技術だ。
AND、OR、XOR、NOT——4つの基本演算
- AND (&) — 両方の入力ビットが1の場合のみ結果ビットは1になります。特定のフラグが立っているかを確認するのに使います。
- OR (|) — 入力ビットの少なくとも一方が1の場合、結果ビットは1になります。複数のフラグを1つの値にまとめるのに使います。
- XOR (^) — 入力ビットが異なる場合、結果ビットは1になります。同じ値でXORを2回適用すると元の値に戻ります。
- NOT (~) — 数値のすべてのビットを反転します。
ビットANDが論理ANDとどう違うか
論理AND(ほとんどの言語で&&)はブール値全体を扱いtrue/falseを返しますが、ビットAND(&)は2つの数値の各ビットを個別に処理し、数値を返します。この2つを混同することはバグのよくある原因で、言語によっては型エラーすら出ずにコンパイルが通ってしまうのが厄介な点です。
このツールが進数変換ツールとセットになる理由
フラグ値が10進数の18だと、どのビットが立っているか一目ではわかりませんが、同じ値を0b10010と書けば、どのビットが有効かすぐに見えます。だからこそビット演算はほとんどの場合、10進数ではなく2進数か16進数で考えられます——AND・OR・XORが視覚的に意味を持つ前に、進数変換ツールで表示を切り替えるのが実務での最初の一歩です。
なぜこれが必要か
- 複数のブールフラグのセットを1つの数値に効率的に格納・チェックする。
- ネットワークプロトコルやバイナリ形式を扱う低レベルコードを理解する。
- ビット演算が通常の算術より高速な計算を最適化する。
演算子優先順位の落とし穴
ほとんどのプログラミング言語では、ビット演算子の&と|は比較演算子よりも優先順位が低くなっています——そのため、if (a & b == c)のような式は、書いた人が期待するのとは異なり、実際にはa & (b == c)として評価されます。これはビットマスクを扱う際に見つけにくいバグの最も一般的な原因の一つであり、これを避ける確実な方法は、ビット演算を常に明示的な括弧で囲むことです。