[C++] 비트 논리 연산자의 사용
두 값을 2진수로 변환한 뒤 비트 단위로 연산하여 값을 반환한다.
그리고 비트 논리 연산자는 아래와 같이 4가지가 존재하는데 연산 방법은 다음과 같다.
& | AND | 두 비트가 모두 1이어야 참 |
| | OR | 두 비트 중 하나라도 1이라면 참 |
~ | NOT | 비트를 반전시킨다. |
^ | XOR | 두 비트가 서로 다르면 참 |
연산 예시를 들어보자.
379와 296을 연산하기 위해서 우선 두 수를 2진수로 변환한다.
- 379 : 101111011 (2진수)
- 296 : 100101000 (2진수)
그리고 각 비트마다 연산을 진행해보자.
and 연산을 실시하면?
두 비트가 모두 1이어야 참이므로 왼쪽부터 연산을 진행하면 결과값은 아래와 같이 반환된다.
100101000
이 값을 10진수로 변환시키면 296이다.
따라서, 반환값은 296이다.
or 연산을 실시하면?
두 비트 중 하나라도 1이어야 참이므로 왼쪽부터 연산을 진행하면 결과값은 아래와 같이 반환된다.
101111011
이 값을 10진수로 변환시키면 379이다.
따라서, 반환값은 379이다.
not 연산을 실시하면?
비트 값을 반전시킨다. 379에 not 연산을 실시하면 아래와 같이 나타난다
010000100
이 값을 10진수로 변환시키면 132이다.
따라서, 반환값은 132이다.
xor 연산을 실시하면?
두 비트 값이 달라야 참이므로 왼쪽부터 연산을 실시하면 아래와 같이 나타난다.
001010011
이 값을 10진수로 변환시키면 83이다.
논리 비트 연산은 어디에 쓰일까?
2진수로 변환한 뒤 계산하기 때문에 일반적인 연산에 비해서 속도가 훨씬 빠르다.
그럼 C++에서 이런 비트연산은 어디에 쓰이는 것일까?
게임에서의 논리 비트 사용 (버프)
대표적으로 게임에서 상태, 버프 등을 표시할 때 사용할 수 있다. 각 비트 자리를 버프의 상태라고하고, 0이 버프가 꺼진 상태, 1이 버프가 켜진 상태라고 해보자.
즉, 버프가 켜졌는지 여부를 1111, 1010, 등 으로 표현을 하고, 0000과 논리 비교를 하면 어떤 버프가 켜졌고 어떤 버프가 꺼졌는지 정수로 표현이 가능하다.
ex) 버프가 5개일 경우
00000 (버프가 모두 꺼짐)
10110 (1, 3, 4 번 버프가 켜짐.)
const int reset_buf_all = 0;
const int attack = 0x1; // (00001)
const int armor = 0x2; // (00010)
const int for_hp = 0x4; // (00100)
const int for_mp = 0x8; // (01000)
const int critical = 0x10; // (10000)
int buf = 0; // 00000
이렇게 16진수를 이용해서 각 버프의 상태를 상수로 부여할 수 있다.
이때, 신기하게도 | (or) 연산을 사용해서 버프를 켤 수 있다. |
buf = buf | attack; // 공격 버프가 켜짐. (00001)
buf = buf | armor; // 방어 버프가 켜짐 (00010)
// 현재 공격, 방어 버프가 켜진 상태 (buf = 00011)
buf = reset_buf_all; // 버프 전체 초기화 (buf = 00000)
buf = buf | (attack + armor); // 공격 및 방어 버프가 켜짐(00011)
buf = buf | critical; // 크리티컬 버프가 켜짐 (10011)
그리고 and 연산을 사용해서 버프의 상태를 확인할 수 있다.
std::cout << "Attack : " << (buf & attack) << std::endl;
// 1 (0이 아님. 버프가 켜진 상태)
std::cout << "armor : " << (buf & armor) << std::endl;
// 2 (0이 아님. 버프가 켜진 상태)
std::cout << "HP : " << (buf & for_hp) << std::endl;
// 0 (0임. 버프가 꺼진 상태)
std::cout << "MP : " << (buf & for_mp) << std::endl;
// 0 (0임. 버프가 꺼진 상태)
std::cout << "critical : " << (buf & critical) << std::endl;
// 16(0이 아님. 버프가 켜진 상태)
프로그래밍 언어에선 값이 0이면 거짓, 0이 아니라면 참임을 이용해서 참과 거짓을 판별할 수 있다. 이를 이용해서 and연산을 통해서 버프의 상태를 확인할 수 있다.
그리고 xor 연산을 통해서 버프를 켜거나 끌 수 있다.
buf = buf ^ armor;
std::cout << "armor : " << (buf & armor) << std::endl;
// 0 (0임. 아머 버프가 꺼졌음.)
std::cout << "현재 버프 상태 : " << buf << std::endl;
// 17 (10001)
// 단, 여기서 한번 더 xor 연산을 해버릴 경우
buf = buf ^ armor;
std::cout << "현재 버프 상태 : " << buf << std::endl;
// 19 (10011) 버프가 다시 켜진다.
다시 정리하면 이렇게 된다.
- & 연산을 통해서 버프의 상태를 확인할 수 있다.
- | 연산을 통해서 버프를 킬 수 있다.
- ^ 연산을 통해서 버프를 켜고 끌 수 있다.