18. 비트 연산자
1. 키워드
- 비트 연산자
- 플래그(Flag)
2. 비트 연산자 사용하기
- 지금까지 자료형을 바이트 단위로 구분하여 사용했다.
- 비트 연산자는 바이트 단위보다 더 작은 비트 단위로 연산하는 연산자이다.
1] 비트(Bit)
- 2진수를 저장하는 단위이다.
- 컴퓨터에서 사용할 수 있는 최소 단위이며
0
과1
을 나타낸다.
2] 바이트(Byte)
8
비트 크기의 단위이다.
- 다음은 비트 연산자의 종류이다.
- 비트 연산자는 비트로 옵션을 설정할 때 주로 사용하며 저장 공간을 아낄 수 있는 장점이 있다.
- 특히 이런 방식을 플래그라고 부른다.
3. 비트 AND, OR, XOR 연산자 사용하기
- 이제 비트 연산자를 사용하여 값을 계산해 보자.
#include <stdio.h>
int main()
{
unsigned char num1 = 1; // 0000 0001
unsigned char num2 = 3; // 0000 0011
printf("%d\n", num1 & num2); // 0000 0001: 01과 11을 비트 AND하면 01이 됨
printf("%d\n", num1 | num2); // 0000 0011: 01과 11을 비트 OR하면 11이 됨
printf("%d\n", num1 ^ num2); // 0000 0010: 01과 11을 비트 XOR하면 10이 됨
return 0;
}
// 1
// 3
// 2
- 각 줄에 해당 값의 10진수와 2진수(비트)를 적어놓았다.
unsigned char
타입에1
을 할당했을 때 비트로 표현하면0000 0001
이다.- 마찬가지로
3
은0000 0011
이다. - 비트 연산은 두 값을 비트 단위로 나열한 뒤 각 자릿수를 비트 연산자로 연산한다.
- 각 자릿수의 연산은 독립적이며 다른 자릿수에 영향을 주지 않는다.
- 그리고 비트 단위로 연산한 각 자릿수를 모두 모으면 최종 결과가 된다.
&
연산자는 비트 AND이므로 두 비트가 모두1
일 때1
이다.- 따라서 하나라도
0
이면0
이 나온다. - 즉,
0000 0001
과0000 0011
을 비트 AND 연산했을 때0 & 1
은0
그리고1 & 1
은1
이 나오므로0000 0001
이 된다. - 10진수로 표현하면
1 & 3
은1
이 된다.
- 다음은
120 & 26
연산이다.
0001 1000
이 나오므로 10진수로24
가 된다.
|
연산자는 비트 OR이므로 두 비트 중 하나만1
이라도1
이다.- 따라서 두 비트가 모두
0
일 때만0
이다. - 즉,
0000 0001
과0000 0011
을 비트 OR 연산했을 때0 | 1
은1
그리고1 | 1
은1
이 나오므로0000 0011
이 된다. - 10진수로 표현하면
1 | 3
은3
이다.
^
연산자는 비트 XOR이므로 두 비트가 다를 때1
이다.- 따라서
1
과1
일 때,0
과0
일 때는 모두0
이다. - 즉,
0000 0001
과0000 0011
을 비트 XOR 연산했을 때0 ^ 1
은1
그리고1 ^ 1
은0
이 나오므로0000 0010
이 된다. - 10진수로 표현하면
1 ^ 3
은2
이다.
4. 비트 NOT 연산자 사용하기
- 이번에는
~
연산자를 사용해 보자.
#include <stdio.h>
int main()
{
unsigned char num1 = 162; // 162: 1010 0010
unsigned char num2;
num2 = ~num1;
printf("%u\n", num2); // 0101 1101: num1의 비트 값을 뒤집음
return 0;
}
// 93
~
연산자는 비트 NOT 연산자이다.- 간단하게
0
은1
로1
은0
으로 바꾸며 "비트를 뒤집는다" 또는 "비트 반전"이라고 말한다. 1010 0010
의 각 비트를 뒤집으면0101 1101
이 되고, 10진수로93
이다.- 즉,
~162
는93
이다.
unsigned char
자료형을 사용하는 이유는?
unsigned char
는 부호 없는 정수이며1
바이트 크기이다.- 비트 연산으로 인해 부호 비트가 영향을 받지 않도록 부호 없는 자료형을 사용했다.
5. 시프트 연산자 사용하기
- C에서 비트의 논리 연산뿐만 아니라 각 자리를 이동시킬 수도 있다.
- 이번에는 비트의 자리를 이동시켜 보자.
#include <stdio.h>
int main()
{
unsigned char num1 = 3; // 3: 0000 0011
unsigned char num2 = 24; // 24: 0001 1000
printf("%u\n", num1 << 3); // 0001 1000: num1의 비트 값을 왼쪽으로 3번 이동
printf("%u\n", num2 >> 2); // 0000 0110: num2의 비트 값을 오른쪽으로 2번 이동
return 0;
}
// 24
// 6
- 시프트 연산자를 사용하여 각 변수의 비트를 지정한 횟수대로 이동했다.
- 다음은 시프트 연산을 하는 방법이며
<<
연산자를 예로 들었다.
- 시프트 연산은
변수 << 이동할 비트 수
또는변수 >> 이동할 비트 수
형식으로 사용한다. - 즉, 지정한 횟수대로 비트를 이동시키며 모자라는 공간은
0
으로 채운다. - 연산자 모양 그대로
<<
는 왼쪽,>>
는 오른쪽 방향이다.
num1 << 3
은0000 0011
을 왼쪽으로3
번 이동하므로0001 1000
이 되고, 10진수로24
이다.
num2 >> 2
는0001 1000
이 오른쪽으로2
번 이동하므로0000 0110
이 되고, 10진수로6
이다.
3 << 3
은 \(3 * 2^3
\)과 같으므로24
가 되고,24 >> 2
는 \(24 / 2^2
\)과 같으므로6
이 된다.- 즉, 시프트 연산
<<
은 2의 거듭제곱을 곱하기,>>
은 2의 거듭제곱을 나누기이다.
6. 비트 연산 후 할당하기
- 이번에는 비트 연산자와 할당 연산자를 함께 사용해 보자.
#include <stdio.h>
int main()
{
unsigned char num1 = 4; // 4: 0000 0100
unsigned char num2 = 4; // 4: 0000 0100
unsigned char num3 = 4; // 4: 0000 0100
unsigned char num4 = 4; // 4: 0000 0100
unsigned char num5 = 4; // 4: 0000 0100
num1 &= 5; // 5(0000 0101) AND 연산 후 할당
num2 |= 2; // 2(0000 0010) OR 연산 후 할당
num3 ^= 3; // 3(0000 0011) XOR 연산 후 할당
num4 <<= 2; // 비트를 왼쪽으로 2번 이동한 후 할당
num5 >>= 2; // 비트를 오른쪽으로 2번 이동한 후 할당
printf("%u\n", num1); // 0000 0100: 100과 101을 비트 AND하면 100이 됨
printf("%u\n", num2); // 0000 0110: 100과 010을 비트 OR하면 110이 됨
printf("%u\n", num3); // 0000 0111: 100과 011을 비트 XOR하면 111이 됨
printf("%u\n", num4); // 0001 0000: 100을 왼쪽으로 2번 이동하면 10000이 됨
printf("%u\n", num5); // 0000 0001: 100을 오른쪽으로 2번 이동하면 1이 됨
return 0;
}
// 4
// 6
// 7
// 16
// 1
- 각 자리별로 10진수와 2진수를 적어놓았다.
&=
는 다른 값과 비트 AND 연산을 한 뒤 다시 자기 자신에게 할당한다는 뜻이다.- 다른 연산자도 마찬가지로 해당 연산을 수행한 뒤 다시 자기 자신에게 할당한다.
- 여기서는 각 변수에
4
가 들어있다.
num1 &= 5
는0000 0100
과0000 0101
을 비트 AND 연산했을 때1 & 1
은1
,0 & 0
은0
,0 & 1
은0
이 나오고 이 값을 다시 할당해서0000 0100
이 된다.
num2 |= 2
는0000 0100
과0000 0010
을 비트 OR 연산했을 때1 | 0
은1
,0 | 1
은1
,0 | 0
은0
이 나오고 이 값을 다시 할당해서0000 0110
이 된다.
num3 ^= 3
은0000 0100
과0000 0011
을 비트 XOR 연산했을 때1 ^ 0
은1
,0 ^ 1
은1
,0 ^ 1
은1
이 나오고 이 값을 다시 할당해서0000 0111
이 된다.
num4 <<= 2
는0000 0100
을 왼쪽으로2
번 이동한 뒤 다시 할당하여0001 0000
이 된다.
num5 >>= 2
는0000 0100
을 오른쪽으로2
번 이동한 뒤 다시 할당하여0000 0001
이 된다.
- 즉, 기존에 들어있던 값은 사라지고 새로 연산한 값이 할당된다.
- 이 연산을 풀어보면 다음과 같다.
num1 = num1 & 5; // 5(0000 0101) AND 연산 후 할당
num2 = num2 | 2; // 2(0000 0010) OR 연산 후 할당
num3 = num3 ^ 3; // 3(0000 0011) XOR 연산 후 할당
num4 = num4 << 2; // 비트를 왼쪽으로 2번 이동한 후 할당
num5 = num5 >> 2; // 비트를 오른쪽으로 2번 이동한 후 할당
- 출력 결과는 앞의 연산 결과와 같다.
- 즉,
&=
,|=
,^=
,<<=
,>>=
연산자는 반복되는 변수 부분을 생략하기 위해 사용한다. - 특히, 비트 연산에서 연산과 할당이 한꺼번에 이루어지는 연산자는 플래그를 켜거나 끌 때 유용하게 활용된다.