コンピュータの演算において「マスク」(英: mask)または「ビットマスク」(bit mask)とは、
ビット演算を実行する際に、データの特定のビット群だけを選択的に操作するために使用される、特別なビットパターンを持つ数値データのことです。まるで
顔の特定部分を覆うマスクのように、注目するビット以外を操作対象外として扱えることから、この名前がついています。
一般的なコンピュータプロセッサは、データをバイト(8ビット)や
ワード(通常16ビット、32ビット、64ビットなど)といった単位でまとめて扱います。特定のレジスタやメモリ領域にあるデータのうち、一部のビットだけを直接操作する命令は少ないため、より細かいビット単位の制御が必要な場面では、ビットマスクを用いた
ビット演算が不可欠となります。これにより、バイト内の特定のビットだけをまとめてオンにしたり、オフにしたり、あるいはその状態を確認したりすることが可能になります。
ビットマスクを使った基本的な操作
ビットマスクは、論理演算と組み合わせて使用されます。
特定のビットをオンにする
特定のビット位置にある値を、現在の状態にかかわらず強制的に「1」にするには、ビット単位の
論理和(OR)演算を用います。
論理和では、演算対象のいずれか一方でも「1」であれば結果は「1」となります。「1」とのOR演算は結果を常に「1」にし、「0」とのOR演算は元の値を維持します。したがって、オンにしたいビット位置に対応するマスクデータを「1」とし、それ以外のビット位置を「0」としたビットパターンを使用します。
例: 最下位ビットから4番目のビットをオンにする
10011101 元のデータ
OR 00001000 マスクデータ(4番目だけ1)
= 10011101 結果(4番目が元から1なので変化なし)
10010101 元のデータ
OR 00001000 マスクデータ(4番目だけ1)
= 10011101 結果(4番目が0から1になった)
特定のビットをオフにする
特定のビット位置にある値を、現在の状態にかかわらず強制的に「0」にするには、ビット単位の
論理積(AND)演算を用います。
論理積では、演算対象の両方が「1」である場合にのみ結果は「1」となり、それ以外は「0」となります。「0」とのAND演算は結果を常に「0」にし、「1」とのAND演算は元の値を維持します。したがって、オフにしたいビット位置に対応するマスクデータを「0」とし、それ以外のビット位置を「1」としたビットパターンを使用します。
例: 最下位ビットから4番目のビットをオフにする
10011101 元のデータ
AND 11110111 マスクデータ(4番目だけ0)
= 10010101 結果(4番目が1から0になった)
10010101 元のデータ
AND 11110111 マスクデータ(4番目だけ0)
= 10010101 結果(4番目が元から0なので変化なし)
個々のビットの状態を調べる
特定のビットが「0」か「1」かを確認するには、AND演算と組み合わせます。調べたいビット位置だけを「1」とし、それ以外のビット位置を「0」としたマスクデータを用いてAND演算を行います。結果がゼロ(すべてのビットが「0」)であれば、調べたビットは元々「0」であったと分かります。結果がゼロでなければ、調べたビットは「1」であったと分かります。具体的にどんな値になったかを気にする必要はなく、ゼロかどうかの比較だけで判断できます。
例: 最下位ビットから4番目のビットの状態を調べる
10011101 元のデータ
AND 00001000 マスクデータ(注目ビットだけ1)
= 00001000 結果(ゼロではないので、4番目のビットは1)
10010101 元のデータ
AND 00001000 マスクデータ(注目ビットだけ1)
= 00000000 結果(ゼロなので、4番目のビットは0)
ビット値を反転させる
特定のビット、またはすべてのビットの値を反転(「0」を「1」に、「1」を「0」に)させるには、ビット単位の
排他的論理和(XOR)演算を用います。XOR演算では、演算対象のビットの値が異なる場合にのみ結果が「1」となります。「1」とのXOR演算は元の値を反転させ、「0」とのXOR演算は元の値を維持します。したがって、反転させたいビット位置に対応するマスクデータを「1」とし、元の値とXOR演算を行います。
例: すべてのビットを反転する
10011101 元のデータ
XOR 11111111 マスクデータ(すべて1)
= 01100010 結果(すべてのビットが反転)
ビットマスクの応用例
ビットマスクは様々な場面で活用されています。
関数の引数でのフラグ指定
複数のブーリアン(真偽値)型のオプションを関数に渡す際に、それぞれのオプションに固有のビットを割り当て、それらを組み合わせたビットマスクを一つの引数として渡す手法があります。これにより、引数の数を減らし、関数呼び出しのオーバーヘッドを削減できます。例えば、
OpenGLの`glClear`関数は、クリアするバッファの種類(色、深度など)をビットマスクで指定します。この手法は、組み合わせが容易で柔軟性が高い反面、単なる整数値として扱われるため、意図しない値が渡されてもコンパイル時にエラーを検出できない場合があります。
C++などでは、型安全性を高めるための工夫がなされることもあります。
2のべき乗による剰余計算
数値を2のべき乗(2^n)で割った余りを求める場合、通常は遅い
剰余演算を行う代わりに、ビットマスクを用いることで計算を高速化できます。法が2^nであれば、その
剰余は元の数値と (2^n - 1) をマスクデータとしたAND演算の結果と等しくなります。これは、2^n - 1 という数値が、バイナリ表現で最下位からn個のビットがすべて「1」になるため、AND演算によって下位nビットだけを取り出すことができるためです。
ハッシュテーブルのインデックス計算などで利用されます。
ネットワーク通信において、
IPアドレスのアクセス制御リスト(ACL)などで特定のアドレス範囲を指定する際にビットマスクが使われます。ここで用いられるマスクは「ワイルドカードマスク」または「逆マスク」とも呼ばれ、
IPアドレスのどの部分を厳密に一致させるか(マスクのビットが0)、どの部分を無視するか(マスクのビットが1)を示します。一般的な
サブネットマスクとは逆の考え方をします。
画像を別の背景画像の上に重ねて表示する際に、重ねる画像のどの部分を透過させるかを指定するためにビットマスクが用いられることがあります。重ねたい画像データとは別に、描画しない(透過させる)
ピクセルに対応するビットを「1」、描画する
ピクセルに対応するビットを「0」としたビットマップ(マスク画像)を用意します。このマスク画像と背景画像をAND演算し、次に元の画像データとOR演算することで、背景画像の上にマスクで指定された形状の画像が合成されます。ポインターカーソルやスプライトなどの描画に使われましたが、現在では
アルファチャンネルといったより高度な透過表現手法が一般的になっています。
これらの例からわかるように、ビットマスクはコンピュータのデータ操作における基本的ながら強力な技術であり、様々なレベルで効率的かつ柔軟な処理を実現するために広く利用されています。