C++でビットフラグを実装してみよう

ビットフラグを扱う上で、ビット操作の基本がわかっていることが前提となりますので、基本をまだ抑えていない方は先にこの記事を読むことをおすすめします。
https://qiita.com/maihei541/items/3ce1cd106a57ceef72c0
# ビットフラグとは
ビットフラグとは、int型の数値を利用して、ビットの各桁をフラグとして利用するもののことです。
# 使い道
複数のフラグが必要になる場合、bool型の値を複数用意するのは非常にメモリ効率が悪い上に、可読性の低下につながります。
そのため、ビットフラグを使用してメモリ効率を上げることで、アプリケーションのパフォーマンス向上に繋げているものがあります。
# 実装
```C++:BitFlag.cpp
#include <iostream>
//フラグの定義
enum FLAGS {
	FLAG_A = 1 << 0,
	FLAG_B = 1 << 1,
	FLAG_C = 1 << 2,
};

//どのフラグがたっているかを確認する関数
void CheckFlags(int flags) {
	//flagsとFLAG_Aの論理積が0でなければ
	if ((flags & FLAG_A) != 0) {
		printf_s("is FLAG_A\n");
	}
	if ((flags & FLAG_B) != 0) {
		printf_s("is FLAG_B\n");
	}
	if ((flags & FLAG_C) != 0) {
		printf_s("is FLAG_C\n");
	}
	printf_s("CheckFinish\n\n");
}

//メイン関数
int main() {
	int flags = 0;//ビットフラグの宣言
	CheckFlags(flags);
	flags |= FLAG_A;//フラグAを追加
	CheckFlags(flags);
	flags |= FLAG_C;//フラグCを追加
	CheckFlags(flags);
	flags &= ~FLAG_C;//フラグCを削除
	CheckFlags(flags);

	system("pause");
	return 0;
}
```
```:result
CheckFinish

is FLAG_A
CheckFinish

is FLAG_A
is FLAG_C
CheckFinish

is FLAG_A
CheckFinish
```
このようにして実装を行いますが、細かく分けて何をしているか見ていきます。
## フラグ列挙体の定義
```C++
enum FLAGS {
	FLAG_A = 1 << 0,
	FLAG_B = 1 << 1,
	FLAG_C = 1 << 2,
};
```
の部分でフラグとなる列挙体を定義しています。
左ビットシフトを行って、二の累乗の数を列挙しています。
二進数で見ると
``FLAG_A``...``0001``
``FLAG_B``...``0010``
``FLAG_C``...``0100``
と、桁が一つずつ違う二進数を列挙しているのが分かると思います。
## フラグの追加
```C++
flags |= FLAG_A;//フラグAを追加
```
``|=``は、左オペランドと右オペランドの論理和を左オペランドに代入するという演算子です。
これも二進数にして考えてみます。
``FLAG_A``は``0001``でした。
例えば、
``flags``が``0000``だとすると、二つの論理和は``0001``となります。
他のパターンも考えてみます。
``flags``...``0010``だと``flags | FLAG_A``...``0011``
``flags``...``0001``だと``flags | FLAG_A``...``0001``
``flags``...``1100``だと``flags | FLAG_A``...``1101``
これらの結果を見ても、``flags |= フラグ列挙体``の操作は、ビットの各桁をboolに見立てたとき、任意の桁にtrueを代入する操作に等しいことが分かり、これはフラグの追加を行っているといえるでしょう。
## フラグの削除
```C++
flags &= ~FLAG_C;//フラグCを削除
```
``&=``は、左オペランドと右オペランドの論理積を左オペランドに代入する演算子。
``~``は論理否定の演算子でした。
これも二進数にして考えてみます。
``~FLAG_C``...``1011``ですよね。
何パターンか論理積を考えてみたいと思います。
``flags``...``0010``だと``flags & ~FLAG_C``...``0010``
``flags``...``1111``だと``flags & ~FLAG_C``...``1011``
``flags``...``1101``だと``flags & ~FLAG_C``...``1001``
このように、各桁をbool値フラグ列挙体が1を持っている桁のみにfalseを代入することと同義になるため、上のコードがフラグの削除となっているといえます。
## フラグが立っているかの確認
```C++
//どのフラグがたっているかを確認する関数
void CheckFlags(int flags) {
	//flagsとFLAG_Aの論理積が0でなければ
	if ((flags & FLAG_A) != 0) {
		printf_s("is FLAG_A\n");
	}
	if ((flags & FLAG_B) != 0) {
		printf_s("is FLAG_B\n");
	}
	if ((flags & FLAG_C) != 0) {
		printf_s("is FLAG_C\n");
	}
	printf_s("CheckFinish\n\n");
}
```
フラグが立っているかを確認しているわけですが、問題は``(flags & FLAG_A) != 0``の部分ですよね。
これも二進数にして考えてみましょう。
``FLAG_A``は``0001``でしたよね。
何パターンか``flags``の値を変えて考えて見たいと思います。
``flags``...``0010``だと``flags & FLAG_A``...``0000``
``flags``...``0001``だと``flags & FLAG_A``...``0001``
``flags``...``1110``だと``flags & FLAG_A``...``0000``
``flags``...``1111``だと``flags & FLAG_A``...``0001``
こういった具合で、フラグ列挙体との論理積を検証する行為は、そのフラグが司る桁が``0``であれば``0``、``1``であれば、それがどの桁であっても``0``以外になることがわかります。
つまり、``flags``とフラグ列挙体の論理積を``!=``で検証する行為は、bool値の検証であるといえます。
# 総括
ビットフラグを用いることによって、簡潔なフラグ管理が可能になります。
C++のライブラリなどを使用するに当たって、ビットフラグを使う場面もあると思うので、ライブラリを自作しない人でも、覚えておくと活躍する場面があるかと思います。