ビット演算 のバックアップの現在との差分(No.3)


  • 追加された行はこの色です。
  • 削除された行はこの色です。
C言語によるビット演算について

C言語のビット演算子は次のものがある。
|演算子||
|演算子||h
|&|AND(論理積)|
|||OR(論理和)|
|^|EX-OR(排他的論理和)|
|~|NOT(否定)|
|>>|右シフト|
|<<|左シフト|

・&#x26;(AND),&#x7c;(OR),&#x5e;(EX-OR)
2項演算子。2入力のビット毎に演算する。
真理値表は以下の通り
|A|B|A&#x26;B|A&#x7c;B|A&#x5e;B|
|A|B|A&#x26;B|A&#x7c;B|A&#x5e;B|h
|0|0|0|0|0|
|0|1|0|1|1|
|1|0|0|1|1|
|1|1|1|1|0|

使用例)
01010101 &#x26; 11001100 => 01000100
01010101 &#x7c; 11001100 => 11011101
01010101 &#x5e; 11001100 => 10011001

・~(NOT)
1項演算子。入力のビットをすべて反転する。
真理値表は以下の通り
|A|&#x7e;A|
|A|&#x7e;A|h
|0|1|
|1|0|

使用例)
&#x7e; 01010101 => 10101010

・<<,>>
2項演算子。左側の入力を右側の入力ビット分シフトする。
左シフトでは、左側で桁をオーバーした分は捨てられ、右側からは0が入れられる。
使用例)
01010101 << 3 => 10101000

右シフトでは、右側でオーバーした分は捨てられ、左側は処理系依存。
論理シフトする処理系では0が、算術シフトする処理系では符号が入る。
符号なし整数型を使えば必ず0が入る。
使用例)
01010101 >> 3 => 00001010

~
・使用例
ビット演算はフラグ処理などに用いることができる。
ANDは指定ビットを0にでき、ORは指定ビットを1にでき、EX-ORは指定ビットの反転ができる。
例えば変数Flagsの2ビット目を1にする(フラグを立てる)には次のようにすればよい。
Flags &#x7c;= 0x04//00000100;
#code(cpp){{
Flags |= 0x04//00000100;
}}
逆に2ビット目を0にする(フラグを折る)には次のようにする。
Flags &#x26;= 0xFC//11111011;
#code(cpp){{
Flags &= 0xFC//11111011;
}}
より一般にnビット目に対して次のようにしてフラグを立てたり折ったりできる。
Flags &#x7c;= 1 << n;
Flags &#x26;= ~(1 << n);
#code(cpp){{
Flags |= 1 << n;
Flags &= ~(1 << n);
}}
フラグが立っているかどうかの確認は次のように行う。
if(Flags &#x26; 1 << n)

#code(cpp){{
if(Flags & 1 << n)
}}
列挙型とマクロを用いて次のようにまとめることもできる。
unsigned char Flags=0; // 最大8個のフラグが使用可能とする
enum FlagName = {GameStart,ItemGet,TalkEnd,Present} //フラグの用途に応じて適切な名前を付ける
#define FLAG_ON(FNAME) (Flags&#x7c;=1<<FNAME)
#define FLAG_OFF(FNAME) (Flags&#x26;=~(1<<FNAME))
#define FLAG_CHECK(FNAME) (Flags&#x26;1<<FNAME)
#code(cpp){{
unsigned char Flags=0;
enum FlagName = {GameStart,ItemGet,TalkEnd,Present}
#define FLAG_ON(FNAME) (Flags|=1<<FNAME)
#define FLAG_OFF(FNAME) (Flags&=~(1<<FNAME))
#define FLAG_CHECK(FNAME) (Flags&1<<FNAME)
}}

次のように使える
#code(cpp){{
FLAG_ON(ItemGet);

...
if(!FLAG_CHECK(ItemGet)){
    printf("まだアイテムを持っていない!");
    printf("I don't have the item.");
}

}}
マクロではなく関数を使ってもいいし、クラスにまとめても良い。
8個より多いフラグを使いたい場合は次のように配列にしたりしても良い。
unsigned char Flags[32]={0}; // 最大256個のフラグが使用可能
enum FlagName = {GameStart,ItemGet,TalkEnd,Present} //フラグの用途に応じて適切な名前を付ける
#define FLAG_ON(FNAME) (Flags[FNAME/8]&#x7c;=1<<FNAME%8)
#define FLAG_OFF(FNAME) (Flags[FNAME/8]&#x26;=~(1<<FNAME%8))
#define FLAG_CHECK(FNAME) (Flags[FNAME/8]&#x26;1<<FNAME%8)
8個より多いフラグを使いたい場合は次のように配列を用いることもできる。
#code(cpp){{
unsigned char Flags[32]={0};
enum FlagName = {GameStart,ItemGet,TalkEnd,Present}
#define FLAG_ON(FNAME) (Flags[FNAME/8]&=1<<FNAME%8)
#define FLAG_OFF(FNAME) (Flags[FNAME/8]&=~(1<<FNAME%8))
#define FLAG_CHECK(FNAME) (Flags[FNAME/8]&1<<FNAME%8)
}}

ただし最近ではこのようなフラグ管理を行う機会は少ないと思われる。
よほどフラグの数が多くならない限り、bool型の変数を利用すればよい。

長々と書いたがこういったフラグ管理は余り使わないだろうとは思う。