- 3.5.1 비트 플래그(Bit Flags)
- 3.5.2 비트 마스크(Bit Masks)
3.5.1 비트 플래그(Bit Flags)
이전 포스팅에서 비트 연산에 대하여 다루었다. 이를 활용하는 방법 중 하나가 바로 비트 플래그가 되겠다. 기본 자료형의 경우 바이트 단위로 끊어지는데 가장 작은 1 byte가 8 bit이지만 하나의 데이터만 담을 수 있게 된다. 하지만 비트 플래그를 사용하게 되면 1 byte를 8 bit로 다룰 수 있게 되고 최대 8개의 정보를 담을 수 있게 된다.
#include <iostream>
using namespace std;
int main()
{
bool item1_flag = false;
bool item2_flag = false;
bool item3_flag = false;
bool item4_flag = false;
// event!
item1_flag = true;
// die! item2 los
item2_flag = false;
if (item3_flag == true)
{
// event
}
if (item3_flag == true && item4_flag == false)
{
item3_flag == false;
item4_flag == true;
}
return 0;
}
우선 비트 플래그가 아닌 일반적인 상황 중 게임에서 아이템 소지 여부에 대해 생각을 해보자. 아이템이 총 4가지가 있고 최초의 상태는 모든 아이템을 가지고 있지는 않게 된다. 그것을 나타내기 위해 boolean 자료형 4개를 사용하였다. 이벤트가 발생하고 1번 아이템을 습득하면 true로 소지하고 있음을 표현한다. 반대로 잃는 경우는 false로 하면 되겠다.
이렇게 아이템 4개의 소지 유무를 4개의 boolean 자료형으로 표현하다 보니 4 byte를 사용하게 되었다. 용량을 줄이기 위하여 비트 플래그를 통해 하나의 아이템 소지 유무를 1 bit로 표현해보자!
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
const unsigned char opt0 = 1 << 0;
const unsigned char opt1 = 1 << 1;
const unsigned char opt2 = 1 << 2;
const unsigned char opt3 = 1 << 3;
cout << bitset<8>(opt0) << endl;
cout << bitset<8>(opt1) << endl;
cout << bitset<8>(opt2) << endl;
cout << bitset<8>(opt3) << endl;
unsigned char items_flag = 0;
cout << "No item " << bitset<8>(items_flag) << endl;
// item0 on
items_flag |= opt0;
cout << "Item0 obtained " << bitset<8>(items_flag) << endl;
// item3 on
items_flag |= opt3;
cout << "Item3 obtained " << bitset<8>(items_flag) << endl;
// item3 lost
items_flag &= ~opt3;
cout << "Item3 lost " << bitset<8>(items_flag) << endl;
// has item1 ?
if (items_flag & opt1) { cout << "Has Item1 " << endl; }
else { cout << "Not have Item1 " << endl; }
// has item0 ?
if (items_flag & opt0) { cout << "Has Item0 " << endl; }
else { cout << "Not have Item0 " << endl; }
// obtain item 2, 3
items_flag |= (opt2 | opt3);
cout << bitset<8>(opt2 | opt3) << endl;
cout << "Item2, 3 obtained " << bitset<8>(items_flag) << endl;
if ((items_flag & opt2) && !(items_flag & opt1))
{
// 가지고 있는걸 잃게 하고 없는걸 가지게 한다.
items_flag ^= opt2;
items_flag ^= opt1;
}
cout << bitset<8>(items_flag) << endl;
return 0;
}
char 자료형 또한 1 byte 크기를 지니고 있으며 8개의 bit 자리를 가지고 있다. 그중 오른쪽 끝 bit부터 순서대로 총 4개의 bit를 opt로 표현하여 상수를 정의한다. opt가 각각 아이템을 의미하며 비트 연산을 통해 각 아이템을 지니게 되고 잃게 됨을 표현할 수 있게 된다.
$$ \begin{align*}&0000\ 0001& &0번\ 아이템\ 소유&\\ &0000\ 0010& &1번\ 아이템\ 소유&\\ &0000\ 1010& &4번\ 아이템과\ 1번\ 아이템\ 소유& \end{align*}$$
3.5.1 비트 마스크(Bit Masks)
비트 플래그는 비트 단위의 0과 1을 조작하는 개념이라면 비트 마스크는 조작된 비트 값에 대해 어떤 값이 존재하는지 체크해주는 것이라고 생각하면 되겠다.
아래의 코드는 비트 마스크를 통해 rgb 값을 red/green/blue에 대한 수치를 뽑아내는 것을 보여주고 있다. rgb color에 대한 table이 궁금하다면 링크를 통해 확인해보자! rgb 각각 1byte를 차지하고 알파를 넣어서 총 4byte로 색을 표현하는 경우도 있다.
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
const unsigned int red_mask = 0xFF0000;
const unsigned int green_mask = 0x00FF00;
const unsigned int blue_mask = 0x0000FF;
cout << bitset<32>(red_mask) << endl;
cout << bitset<32>(green_mask) << endl;
cout << bitset<32>(blue_mask) << endl;
unsigned int pixel_color = 0xDAA520;//0x00DAA520
cout << bitset<32>(pixel_color) << endl;
unsigned char red, green, blue;
blue = pixel_color & blue_mask;
cout << "blue " << bitset<8>(blue) << " " << int(blue) << endl;
green = (pixel_color & green_mask) >> 8;
cout << "green " << bitset<8>(green) << " " << int(green) << endl;
return 0;
}
16진수 표현을 통해 각 색에 대한 비트 마스크 값을 상수로 정의한다. pixel color가 있으면 각 비트 마스크 상수 값을 통해 해당하는 색의 수치만 뽑아내서 표현할 수가 있겠다. C++ 14부터는 비트 마스크를 표현하는 방식이 추가되었는데 링크를 추가해두도록 하겠다!