icon안동민 개발노트

비트 연산자


비트 연산자 개요

 비트 연산자는 정수형 데이터의 개별 비트를 조작하는 데 사용됩니다. 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;
}

주의사항

  1. 부호 있는 정수형에 대한 시프트 연산의 결과는 구현에 따라 다를 수 있습니다.
  2. 비트 연산의 우선순위에 주의해야 합니다. 괄호를 사용하여 의도를 명확히 표현하는 것이 좋습니다.
  3. 0으로 나누는 것과 마찬가지로, 음수 값이나 피연산자의 비트 수보다 큰 값으로 시프트하는 것은 정의되지 않은 동작을 유발할 수 있습니다.

연습 문제

  1. 정수를 입력받아 2진수로 표현하는 프로그램을 작성하세요.
  2. 두 정수를 입력받아 모든 비트 연산의 결과를 출력하는 프로그램을 작성하세요.
  3. 비트 마스킹을 이용하여 RGB 색상 값을 조작하는 프로그램을 작성하세요. (힌트 : 각 색상은 0-255 범위의 값을 가집니다)
  4. 주어진 정수가 2의 거듭제곱인지 확인하는 프로그램을 비트 연산을 사용하여 작성하세요.
  5. XOR 연산을 사용하여 두 변수의 값을 교환하는 프로그램을 작성하세요.


참고 자료