비트 연산자들은 정수값을 구성하는 비트들에 적용된다. 비트 연산자의 종류는 다음과 같다. 왼쪽 시프트 연산자, 오른쪽 시프트 연산자, 비트 논리 연산자, 비트 부정 연산자
시프트 연산자는 왼쪽, 오른쪽이 있다. 왼쪽 시프트 연산자는 다음과 같이 쓴다.
value << shift;
여기서 value는 정수값이고, shift는 시프트 비트 수이다. <<는 시프트 연산자다. 이는 value의 모든 비트들을 왼쪽에 shift만큼 옮기라는 거다. 그게 무슨 말인가? 컴퓨터는 0, 1로 이루어진 2진 데이터다. 숫자 13도 비트로 이루어져 있고, 3도 비트로 이루어져있다. 만약 value가 13이고 shift가 3이면 이런 의미이다.
저런 식으로 비트가 3칸씩 이동하는 거다. 맨 왼쪽의 밀려난 비트들은 사라지고, 오른쪽에 새로 들어온 비트들은 0으로 취급한다. 각 비트의 위치가 각 오른쪽의 비트 위치의 2배의 값을 나타내므로, 3칸 이동하면 2^3을 곱해주면 된다. 그러면 완전 다른 숫자가 돼버린다. 몇 가지 특징을 알아보자.
int x = 20;
int y = x << 3; // 이는 x의 값을 바꾸지 않는다. 마치 int y = x + 3;가 x의 값을 바꾸지 않는 것처럼.
// 만약 변수의 값을 바꾸면서 쓰려면
x = x << 3;
x <<= 3; // 이런 식으로 쓰면 된다.
//여기서 y는 x * 2^3 = 80이 나온다.
오른쪽 시프트 연산자도 이와 비슷하다. 왼쪽 시프트 연산자와는 반대로, 오른쪽으로 비트를 옮긴다.
value >> shift;
왼쪽 시프트와 마찬가지로, 밀려난 부분은 사라지고, 빈 자리는 0으로 채워진다. 한번 써보자.
int x = 20;
int y = x >> 3;
// 만약 변수의 값을 바꾸면서 쓰려면
x = x .> 3;
x >>= 3; // 이런 식으로 쓰면 된다.
우리는 논리 연산자를 배웠다. 예를 들어 부정 연산자는 true 앞에 쓰이면 false, false 앞에 쓰면 true를 반환했다. 비트 부정 논리 연산자도 비슷하다. 차이점은 각각의 비트에 쓰인다는 것이다. 문법은 '~'를 쓰면 된다.
unsigned int x = 13;
unsigned int y = ~x;
// y : 65522
unsigned를 쓰는 이유는, 맨 앞의 부호 비트도 영향을 받기 때문이다.
이와 마찬가지로 비트 OR 연산자와 비트 AND 연산자도, 각각 논리곱 연산자, 논리합 연산자와 비슷하다. 비트 OR 연산자는, 비트가 하나만 1이어도 1이 나오고, 비트 AND 연산자는 비트가 둘 다 1이어야 1이 나온다. 사용은 다음과 같이 |, &를 이용한다.
int a = 10;
int b = 50;
int c = a | b;
int d = a & b;
a |= b; // a를 a|b로 설정한다.
a &= b; // a를 a&b로 설정한다.
그 다음으로는 비트 XOR 연산자가 있는데, 이는 두 비트가 같으면 1, 다르면 0을 산출한다. ^를 사용한다.
int a = 10;
int b = 50;
int c = a ^ b;
a ^= b; // a를 a ^ b로 설정한다.
비트 연산자들은 언제 쓰는가? 파일 입출력 했을 때 open() 메서드의 제2 매개변수 상수를 생각해보자.
잘 보면 1,2,4,8,10,40 순으로 증가한다. 왜 1,2,3,4,5...이런 식으로 증가 안 하는가? 비트 연산으로 사용하기 유리하게 하기 위해서다. 그래서
ios_base::out | ios_base::binary;
이런 식으로 사용할 수 있었던 거다.