[C++] C++에서 사용되는 개념 7-1탄 (비트 플래그)

Patrick!·2023년 1월 8일
0
post-thumbnail

지난 시간에 작성한 [C++] C++에서 사용되는 개념 7탄에 잠깐 등장한 Bit Flag 에 대해 심도 있는 설명을 기록해야 겠다고 생각했다!!

귀찮아서 중요한 부분을 대충 작성해서 올린 것은 비밀 ....

비트 플래그(Bit Flag)가 무엇인가?

바이트의 개별 비트의 개념
메모리의 최소 크기 단위는 1바이트이므로 변수의 크기는 적어도 1바이트 이상이다. 8비트(1바이트)는 비트가 8개이므로 8가지 상태를 저장할 수 있다. 이는 1바이트를 사용해서 1비트만 사용하고 7비트를 낭비함으로써 1가지 상태만 저장하는 형태로 사용한다.

우선 게임의 환경은 언제나 자원과의 싸움이 일어난다.(항상 부족하고 척박한 환경....)

그렇기에 게임안에서 일어나는 모든 프로세스의 메모리를 관리하는 일에 있어 매우 중요하다.

위의 사진은 대한민국의 대표적인 RPG게임 중 하나인 <리니지> 의 화면이다.
캐릭터 위에 노란색 원이 있는데 이는 캐릭터가 상태이상인 스턴 상태를 가리킨다.

다음 사진은 펄어비스의 <검은사막>의 화면이다
캐릭터가 스킬을 사용하자 병사가 눕게 되는데 이는 상태이상인 넉다운 상태를 가리킨다.

우선 다양한 컨텐츠와 요소가 존재하는 RPG 게임을 예로 들어서 설명을 이어 나가보겠다.

위처럼 전투상태에서 오브젝트들의 실시간 상태를 나타내는 요소들이 존재한다. 위의 요소 말고도 다양한 상태이상들이 존재한다. 하지만 이를 전부 변수로 생성한다면 그 만큼의 메모리를 할당하고 소모하게 된다.

이렇게 할당된 메모리는 다른 곳에서 사용될 메모리를 차지하는 경우로 이어져 메모리 부족 현상을 초래하게 될 것이다.

무작정 게임을 만들면서 모든 것들을 기존의 프로그레밍 처럼 작성했다간 프로젝트를 갈아 엎어야할 상황에서 실성하는 자신을 마주하게 될 것이 분명하다.....

그럼 비트 플래그는 어떻게 사용해야 하는가 ?!

우선 Bit Flag 선언 방법 부터 알아보자.

C++에서는 10진법보다 8 & 16 진법과 친숙해져야 한다...

그렇기에 선언방법 또한 16 진법을 사용하는 편이 좋다.

선언할 때, 몇 개의 비트를 통해 상태를 나타낼 것인지를 꼭 정의하고 진행해야한다는 것을 잊지말자.

const unsigned char option01 = 0x1;
const unsigned char option02 = 0x2;
const unsigned char option03 = 0x4;
const unsigned char option04 = 0x8;
const unsigned char option05 = 0x10;
const unsigned char option06 = 0x20;
const unsigned char option07 = 0x40;
const unsigned char option08 = 0x80;

const unsigned를 붙여서 선언하는 것인가?
이유는 간단하다. 비트 플래그로 사용되는 경우, 해당 값들은 다른 프로세스에 의해 원래 값에 변화를 받아서는 안된다.

즉, 오버라이딩이 이루어져서는 안되는 값들이다.
그래서 const 를 사용하여 값을 상수화 하여야 한다.

그리고 Bit Flag는 부호에 대한 영향을 받지 않아야 하기에 unsigned를 사용해주는 것이 일반적이다.

위 처럼 작성하면 좋은 점이 한가지 있다. 앞서 배운 비트 연산을 통해 조작할 수 있다는 것이다!
(이는 뒤에서 다루어 보겠다!)

이제 비트 플래그를 사용할 준비를 마쳤으니 본격적으로 사용해보자!

위에서 선언한 비트 플래그를 사용하기 위한 변수를 작성한다.
unsigned char char_status = 0;

1. 비트 켜기

비트 OR(|) 연산자를 사용하여 작동할 수 있다.

char_status |= option01;

char_status와 option01를 or 연산자를 통해 비트를 활성화 한다고 보면 된다. (활성화에 대한 방법은 다양하게 존재할 수 있다.)

위 처럼 활성화하게 되면 어떤 원리로 진행이 되는거지?

char_status = 0 0 0 0 0 0 0 0
option01    = 0 0 0 0 0 0 0 1 | or 
-----------------------------------
char_status = 0 0 0 0 0 0 0 1

위의 비트 연산을 통해 char_status 의 1바이트 부분이 활성화 된 것을 확인 할 수 있다.

2. 비트 끄기

비트 AND(&) 연산자와 비트 NOT(~) 연산자를 사용하여 작동할 수 있다.

char_status &= ~option01;

그럼 비활성화 되는 원리는 무엇인가?

char_status = 0 0 0 0 0 0 0 1
~option01   = 1 1 1 1 1 1 1 0 & and
-----------------------------------
char_status = 0 0 0 0 0 0 0 0

NOT(~) 연산자의 경우, 비트를 반대로 만드는 옵션이며 이를 AND(&) 연산자와 char_status와 비교하는 원리로 작동한다.

결과적으로 option0x를 ~를 통해 반대의 값으로 만들어 이를 비트 플래그가 적용중인 변수에 비교하여 비트를 조작하는 방식이다.

추가적으로 여러 비트를 동시에 끄게 할 수 있다.

OR(|) 연산자를 통해 여러 비트를 동시에 조작할 수 있다.
char_status &= ~(option01 | option02);

3. 비트 상태 확인

비트 AND(&) 연산자를 이용하여 비트의 상태가 어떤 상태인지 확인 할 수 있다.

if (char_status & option01)
    cout << "char_status의 설정은 01로 되어있다.";
if !(char_status & option05)
    cout << "char_status의 설정은 05로 되어있지 않다.";
    
    & Bit Flag OptionXX 를 통해 설정값과 비교하여 true / false를 구분한다.

이렇게 비트플래그를 사용하면 적은 메모리를 사용하여 성능에 대한 부하를 최소화 할 수 있다는 장점이 매우 부각된다.

하지만 어디까지나 케이스 에 따라 달라지는 것이 coding 이기에 비트플래그가 유용하지 않을 수도 있다 ... 그렇기에 상황에 맞게 사용하는 방법을 터득 하는 것이 좋으니 항상 잊으면 안된다

profile
C++와 Unreal Engine / C#과 Unity / Katalon Studio를 통한 자동화 테스트 등을 하루하루 공부한 기록

0개의 댓글