비트 연산자
비트 연산자 개요
비트 연산자는 정수형 데이터의 개별 비트를 조작하는 데 사용됩니다. C++에서 제공하는 비트 연산자는 다음과 같습니다.
1. 비트 AND &
2. 비트 OR |
3. 비트 XOR ^
4. 비트 NOT ~
5. 왼쪽 시프트 <<
6. 오른쪽 시프트 >>
이 연산자들은 비트 수준에서 작동하므로, 효율적인 연산이 가능하고 특정 상황에서 매우 유용합니다.
비트 연산자 상세 설명
비트 AND 연산자 &
두 피연산자의 대응되는 비트가 모두 1일 때만 1을 반환합니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char b = 0b00110011; // 51 in decimal
unsigned char result = a & b;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "b: " << std::bitset<8>(b) << std::endl;
std::cout << "a & b: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
# 출력
a: 00001111
b: 00110011
a & b: 00000011
Result in decimal: 3
비트 OR 연산자 |
두 피연산자의 대응되는 비트 중 하나라도 1이면 1을 반환합니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char b = 0b00110011; // 51 in decimal
unsigned char result = a | b;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "b: " << std::bitset<8>(b) << std::endl;
std::cout << "a | b: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
a: 00001111
b: 00110011
a | b: 00111111
Result in decimal: 63
비트 XOR 연산자 ^
두 피연산자의 대응되는 비트가 서로 다를 때 1을 반환합니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char b = 0b00110011; // 51 in decimal
unsigned char result = a ^ b;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "b: " << std::bitset<8>(b) << std::endl;
std::cout << "a ^ b: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
a: 00001111
b: 00110011
a ^ b: 00111100
Result in decimal: 60
비트 NOT 연산자 ~
피연산자의 모든 비트를 반전시킵니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char result = ~a;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "~a: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
a: 00001111
~a: 11110000
Result in decimal: 240
왼쪽 시프트 연산자 <<
왼쪽 피연산자의 비트들을 오른쪽 피연산자에 지정된 수만큼 왼쪽으로 이동시킵니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char result = a << 2;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "a << 2: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
a: 00001111
a << 2: 00111100
Result in decimal: 60
오른쪽 시프트 연산자 >>
왼쪽 피연산자의 비트들을 오른쪽 피연산자에 지정된 수만큼 오른쪽으로 이동시킵니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char a = 0b00001111; // 15 in decimal
unsigned char result = a >> 2;
std::cout << "a: " << std::bitset<8>(a) << std::endl;
std::cout << "a >> 2: " << std::bitset<8>(result) << std::endl;
std::cout << "Result in decimal: " << static_cast<int>(result) << std::endl;
return 0;
}
a: 00001111
a >> 2: 00000011
Result in decimal: 3
비트 연산자의 활용
비트 마스킹
특정 비트만 조작하거나 확인하는 기법입니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char flags = 0b00000101;
unsigned char mask = 0b00000010;
bool isBitSet = (flags & mask) != 0;
std::cout << "Flags: " << std::bitset<8>(flags) << std::endl;
std::cout << "Mask: " << std::bitset<8>(mask) << std::endl;
std::cout << "Is bit set? " << std::boolalpha << isBitSet << std::endl;
return 0;
}
비트 토글
특정 비트의 값을 반전시키는 기법입니다.
#include <iostream>
#include <bitset>
int main() {
unsigned char flags = 0b00000101;
unsigned char mask = 0b00000010;
std::cout << "Before toggle: " << std::bitset<8>(flags) << std::endl;
flags ^= mask;
std::cout << "After toggle: " << std::bitset<8>(flags) << std::endl;
return 0;
}
비트 플래그
여러 불리언 값을 하나의 정수에 저장하는 기법입니다.
#include <iostream>
#include <bitset>
enum Flags {
FLAG_A = 1 << 0, // 0001
FLAG_B = 1 << 1, // 0010
FLAG_C = 1 << 2 // 0100
};
int main() {
unsigned char flags = 0;
// 플래그 설정
flags |= FLAG_A;
flags |= FLAG_C;
std::cout << "Flags: " << std::bitset<8>(flags) << std::endl;
// 플래그 확인
bool hasFlag_B = (flags & FLAG_B) != 0;
std::cout << "Has FLAG_B? " << std::boolalpha << hasFlag_B << std::endl;
return 0;
}
주의사항
- 부호 있는 정수형에 대한 시프트 연산의 결과는 구현에 따라 다를 수 있습니다.
- 비트 연산의 우선순위에 주의해야 합니다. 괄호를 사용하여 의도를 명확히 표현하는 것이 좋습니다.
- 0으로 나누는 것과 마찬가지로, 음수 값이나 피연산자의 비트 수보다 큰 값으로 시프트하는 것은 정의되지 않은 동작을 유발할 수 있습니다.
연습 문제
- 정수를 입력받아 2진수로 표현하는 프로그램을 작성하세요.
- 두 정수를 입력받아 모든 비트 연산의 결과를 출력하는 프로그램을 작성하세요.
- 비트 마스킹을 이용하여 RGB 색상 값을 조작하는 프로그램을 작성하세요. (힌트 : 각 색상은 0-255 범위의 값을 가집니다)
- 주어진 정수가 2의 거듭제곱인지 확인하는 프로그램을 비트 연산을 사용하여 작성하세요.
- XOR 연산을 사용하여 두 변수의 값을 교환하는 프로그램을 작성하세요.
참고자료
- C++ 비트 연산 표준 라이브러리 : Bitset
- 비트 해킹 기법 : Bit Twiddling Hacks
- C++ 표준의 비트 연산 관련 내용 : Bitwise operations