ビット操作

こんな時普通は論理演算の話を先にするものなんですがねぇ…(^^
まあ、論理演算を知っていることが前提、ということで…
今回は情報の最小単位「ビット」について説明します。
とりあえずVBの文法で書き、ビットは一番右を第0ビットとして数えることにします。

ビット操作を使う理由

例えばあなたがRPGを作っていたとします(別にRPGじゃなくてもいいんですよ)。
RPGにはよくたくさんの宝箱が出てきますね(宝箱以外でもいいんですけどね)。
宝箱には普通、閉じているか、開いているかの二つの情報しかありませんね。
中身についてはどうせ変わることなんてないでしょうからここでは無視します。
そうすると宝箱は一つにつき1ビットの情報をもっていることになります。
ここで仮に宝箱の数を1000個とすると(1000個でなくてもいいんですが)、宝箱一つ一つの状態を通常の変数に入れた場合、Byte型など、最も小さい単位の変数に入れたとしても、すべての宝箱の状態をあらわすのに1000バイトも使ってしまうのです。
ここで、1バイト=8ビットなので、つまり1000バイトは8000ビットということです。
では、今度はすべて1ビットの変数に入れた場合はどうなるでしょうか。
当然1000バイトの8分の1の125バイトですね。
言い換えれば8000ビットが1000ビットに変わったということになります。
7000ビットの節約ですね。

実際にビット操作を使ってみよう

ところが、現実にはそう都合よくビット型の変数はありません。
だから、複数ビットで構成される普通の変数をビット配列として使うことにします。
…いきなり難しそうな話になりましたね。
でもそんなに難しいことはしません(複雑ということはあり得ますが)。


とりあえず次の式を見てください。

A:128 Or 32 = 160
B:160 Or 32 = 160


この式の意味はわかりますね。
これを8個のビット列としてみてみると

A:10000000 Or 00100000 = 10100000
B:10100000 Or 00100000 = 10100000


こんなふうになります。
ここで、赤色になっているビット(第5ビット)に注目すると、いずれも32(2の5乗)とのOrをとって第5ビットを1にしています。
逆にいえば、どんな数でも第5ビットを1にしたければ2の5乗とOrをとればいいのです。
一般的にいえば、次のようになります。

第nビットを1にする方法
2のn乗とのOrをとる

今度はAndを使ってみましょう。

A:10000000 And 00100000 = 00000000
B:10100000 And 00100000 = 00100000


今回は赤い部分は変わっていませんね。
代わりに他の部分は全部0になっています。
つまり、2の5乗とAndで計算すると、他のビットがどうであるかに関わらず、
計算結果は第5ビットが0であれば0に、1であれば0以外になります。
逆にいえば、2の5乗とAndで計算した結果が0か0以外かを
調べることで第5ビットが0か1かがわかるのです。

第nビットを取得する方法
2のn乗とのAndをとる

次はXorを使ってみます。

A:10000000 Xor 00100000 = 10100000
B:10100000 Xor 00100000 = 10000000


今度は第5ビットが、0だったら1に、1だったら0になってしまいました。
つまり、こういうことです。

第nビットを反転する方法
2のn乗とのXorをとる

あとは第nビットを0にする方法だけですね。
今度は少々強引ですが、次のようにします。

A:10000000 And 11011111 = 10000000
B:10100000 And 11011111 = 10000000


今回は青くなっている部分(左辺第二項)に注目してください
00100000から全ビット反転しています。

第nビットを0にする方法
2のn乗を全ビット反転したものとのAndをとる

VB/C++用サンプルを兼ねたビット操作クラス(1.97kilobyte)

ビットフィールド

06/03/08追記

C言語の構造体などのビットフィールドでは1ビットの変数も可能らしいですが配列にすることは不可能のようです。

// 32ビットに32個のデータ.
struct bf1 {
	unsigned bit00 : 1; unsigned bit01 : 1; unsigned bit02 : 1; unsigned bit03 : 1;
	unsigned bit04 : 1; unsigned bit05 : 1; unsigned bit06 : 1; unsigned bit07 : 1;
	unsigned bit10 : 1; unsigned bit11 : 1; unsigned bit12 : 1; unsigned bit13 : 1;
	unsigned bit14 : 1; unsigned bit15 : 1; unsigned bit16 : 1; unsigned bit17 : 1;
	unsigned bit20 : 1; unsigned bit21 : 1; unsigned bit22 : 1; unsigned bit23 : 1;
	unsigned bit24 : 1; unsigned bit25 : 1; unsigned bit26 : 1; unsigned bit27 : 1;
	unsigned bit30 : 1; unsigned bit31 : 1; unsigned bit32 : 1; unsigned bit33 : 1;
	unsigned bit34 : 1; unsigned bit35 : 1; unsigned bit36 : 1; unsigned bit37 : 1;
};

// これはエラー(ビットフィールドへのポインタは認められない)
struct bf2 {
	unsigned bit[32] : 1;
};