ビットをどう使うかよく判らない人へ

  • 151
    いいね
  • 5
    コメント
この記事は最終更新日から1年以上が経過しています。

結構ストックも増えてきたので、いい加減ご指摘頂いた部分を修正しました…

周りにビットを毛嫌いする人が多かったので、ビットの使い方をなるべく解り易く書いてみようと思いました。

なぜビットを使うのか

*主なメリット

  1. データ量が少なくて済む
  2. 実際速い
  3. 一つのデータに複数の情報を詰め込める

データ量をケチりたい環境では、一つの変数に色んな情報を積みまくったりするし
ビット演算は通常の四則演算より高速な場合も多かったりします。

特に、「1つのデータに複数の情報を詰め込める」というのは、プログラムのロジックでよく応用されるテクニックです。
本記事ではこの場合の具体例を上げてみようかと思います。

なにが分かればいいのか

必要な知識は、この3つです。

  1. ビット演算
  2. ビットフラグ
  3. ビットマスク

これさえ出来れば、プログラムに応用出来るようになるかと思います。

1つの変数に複数のフラグを立ててみる

手順としては

  1. ビットフラグを定義する
  2. 変数にビットフラグを立てる
  3. ビットフラグを抽出する

の3つです。

ビットフラグを作る

// 4byte データ
int BIT_FLAG_1   = 0x0001; // 2進数 : (0000 0000 0000 0001)
int BIT_FLAG_2   = 0x0002; // 2進数 : (0000 0000 0000 0010)
int BIT_FLAG_4   = 0x0004; // 2進数 : (0000 0000 0000 0100)
int BIT_FLAG_8   = 0x0008; // 2進数 : (0000 0000 0000 1000)
int BIT_FLAG_16  = 0x0010; // 2進数 : (0000 0000 0001 0000)
int BIT_FLAG_32  = 0x0020; // 2進数 : (0000 0000 0010 0000)
int BIT_FLAG_64  = 0x0040; // 2進数 : (0000 0000 0100 0000)
int BIT_FLAG_128 = 0x0080; // 2進数 : (0000 0000 1000 0000)

ビットフラグはビット単位で立てます。
2進数で1桁ずつ立っていれば良いので
1ビット目を立てる為には、1を。
2ビット目に立てる為には、2を。
では3ビット目は3…ではなく4です。

2進数なので、桁を上げるには2を掛けていけばいいのです。(10進数は10を掛けると桁が上がりますよね。)

こうして2の倍数で数値を作っていくと、ビットフラグが出来上がります。

余談ですが、何故わざわざ16進数で宣言するのかと言うと、
2進数で表すビットと、視覚的に互換性が高かったりします。
( 0x1234は、(0001 0010 0011 0100) ですが、
 0001(1) 0010(2) 0011(3) 0100(4) と区切りそれぞれに対応します)
なので、整数値で宣言しても特に問題はないです。

変数にフラグを立てる

先ほどのフラグを使って、変数にフラグを立ててみましょう。
"|"とか"&"(ビット演算子)が解らない方は、適当に「C言語 ビット演算」とかでググってみて下さい。

int flag = BIT_FLAG_1 | BIT_FLAG_4 ; // 1つ目と3つ目にフラグを立てる
  • 2進数で見るとこうなります。

(0000 0001) OR (0000 00100) = (0000 0101)

フラグを抽出する

例えば、
立っているフラグそれぞれ別の関数を呼ぶ
という機能を想定してみます。


void main()
{
    // 上記と同じフラグ
    int flag = ( BIT_FLAG_1 | BIT_FLAG_4 );
    bit_extractor(flag);
}

void bit_extractor( int flag )
{
    if( ( flag & BIT_FLAG_1 ) != 0 )
    {   // ここはtrue
        funcA(); 
    }
    if( ( flag & BIT_FLAG_2 ) != 0 )
    {   // ここはfalse
        funcB();
    }
    if( ( flag & BIT_FLAG_4 ) != 0 )
    {   // ここはtrue
        funcC();
    }
    if( ( flag & BIT_FLAG_8 ) != 0 )
    {   // ここはfalse
        funcD();
    }
}
//C言語などifの評価が数値の場合は、 if( flag & BIT_FLAG_1 ) こうやってすっきり書けます。

こうすることで、フラグ変数を複数作ること無く場合分けすることが出来ました。
些細なことですが、パラメータにbool変数を4つ投げるよりすっきりします。

次回

次はバイト単位で情報が格納されているデータから、ビットマスクとビットシフトを使って抽出する方法を説明しようと思います。