비트 연산자
정의
- 정수형(문자형 포함) 값에 대해 비트(bit) 단위로 연산을 수행하는 연산자
종류
| 연산자 | 명칭 | 예제 | 기능 |
|---|---|---|---|
& |
비트 AND Bitwise AND |
a&b |
정수 a와 b의 대응되는 두 비트가 모두 1일 때 결과가 1 |
| |
비트 OR Bitwise OR |
a|b |
” 중 하나라도 1이면 결과가 1 |
^ |
비트 XOR Bitwise XOR |
a^b |
” 가 서로 다를 때만 결과가 1 (Exclusive OR) |
~ |
비트 NOT Bitwise NOT |
~a |
각 비트 1은 0으로, 0은 1로 변환 not true = false / not false = true |
<< |
왼쪽 시프트 Left Shift |
a<<n |
a 의 각 비트를 n 비트씩 왼쪽으로 이동 이동으로 비워지는 공간은 0으로 채워진다. |
>> |
오른쪽 시프트 Right Shift |
a>>n |
a 의 각 비트를 n 비트씩 오른쪽으로 이동 이동으로 비워지는 공간은 0으로 채워진다. |
예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void bit_operator(){
int a = 0B11001000;
int b = 0B00111001;
// & : 비트의 AND 연산
// 둘 다 1이면 1, 그 외는 모두 0
printf("a & b : ");
print_binary(a&b, 8);
// | : 비트의 OR 연산
// 둘 중 하나라도 1이면 1, 둘 다 0이면 0
printf("a | b : ");
print_binary(a|b, 8);
// ^ : 비트의 XOR 연산
// 둘이 다르면 1, 같으면 0
printf("a ^ b : ");
print_binary(a^b, 8);
// ~ : 비트의 NOT 연산
// 0은 1로, 1은 0으로 반전
printf("~a : ");
print_binary(~a, 8);
// a << n : 비트의 좌측 이동
// a의 각 비트를 n자리씩 왼쪽으로 이동
// 빈 공간은 0으로 채워짐
printf("a << n : ");
print_binary(a << 2, 8);
// a >> n : 비트의 우측 이동
// a의 각 비트를 n자리씩 오른쪽으로 이동
// 빈 공간은 0으로 채워짐
printf("a >> n : ");
print_binary(a >> 2, 8);
}
void print_binary(int number, int binary_digits){
// binary 로 출력 (number : 이진수로 변환할 수 / binary_digits : 이진수 자릿수)
for (int i = (binary_digits-1); i >= 0; i--){
int result = (number >> i) & 1;
printf("%d", result);
}
printf("\n");
}
1
2
3
4
5
6
a & b : 00001000
a | b : 11111001
a ^ b : 11110001
~a : 00110111
a << n : 00100000
a >> n : 00110010
비트 연산을 이용한 마스킹
- 비트 연산을 이용해서, 비트 마스킹을 할 수 있다.
- 비트 마스킹이란, 피연산 값의 특정 비트를 필터링(통과, 차단)하거나 반전시키는 것을 의미한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void bit_masking(){
// 00001111 이라는 마스크 비트를 선언, 정의했다.
int mask;
mask = 0B00001111;
// 피연산 비트 값
int a = 0B10110011;
// 앞 네 자리를 지우는 마스크
// 0과 &표시를 하면 상대의 비트값이 뭐든 모두 지워지며
// 1과 &표시를 하면 상대의 비트값이 그대로 유지된다.
printf("& mask : ");
print_binary(a&mask, 8);
// 특정 비트를 1로 채우는 마스크
// 0과 |표시를 하면 상대 비트값이 그대로 유지됨
// 1과 |표시를 하면 연산 결과값이 1이 됨
printf("| mask : ");
print_binary(a|mask, 8);
// 특정 비트값만 반전하기
// 0과 ^표시를 하면 상대 비트값이 1이면 1, 0이면 0으로 그대로 유지됨
// 1과 ^표시를 하면 상대 비트값이 1이면 0, 0이면 1로 바뀜 (반전)
printf("^ mask : ");
print_binary(a^mask, 8);
}
1
2
3
& mask : 00000011
| mask : 10111111
^ mask : 10111100
2 의 거듭제곱 곱하기 및 나누기
- 시프트 연산들은 2의 거듭제곱을 곱하거나 나눈 결과와 같다.
- 왼쪽 시프트 : 2의 거듭제곱 곱하기 연산과 동일
- 오른쪽 시프트 : 2의 거듭제곱 나누기 연산과 동일
- 왼쪽 시프트는 오버플로가, 왼쪽 시프트는 음수에서 부호비트 왜곡이 있을 수 있으므로 주의해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
void square(){
// << : 좌측이동 : 2^n 제곱을 하는 효과
int a = 0B00000100; // 4
int b = a << 3;
printf("%d\n", b); // 4 * 2^3 = 4 * 8 = 32
print_binary(b, 8); // 4 * 2^3 = 4 * 8 = 32
// >> 우측이동 : 2^n 제곱근을 하는 효과
int c = a >>2;
printf("%d\n", c); // 4 / 2^2 = 4 / 4 = 1
print_binary(c, 8); // 4 / 2^2 = 4 / 4 = 1
}
1
2
3
4
5
32
00100000
1
00000001
논리연산과 비교하기
- 논리연산과 비트연산은 그 결과가 다를 수 있다.
- 이 점을 반드시 주의하기!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void vs_logical_operator(){
// 논리 연산자와는 계산 결과가 다르다.
int a = 1;
int b = 2;
int result_of_logical = a && b;
printf("%d\n", result_of_logical);
print_binary(result_of_logical, 8);
int result_of_binary = a & b;
printf("%d\n", result_of_binary);
printf("a : ");
print_binary(a, 8);
printf("b : ");
print_binary(b, 8);
print_binary(result_of_binary, 8);
}
1
2
3
4
5
6
7
8
9
# 논리 연산
1
00000001
# 비트 연산
0
a : 00000001
b : 00000010
00000000
먼저, 위 논리 연산에서는 참 값(1)과 참 값(2)의 AND 연산을 통해 결과값이 참(1)이 된다.
반면에 비트 연산에서는 0001(1) 과 0010(2) 의 AND 연산을 했기 때문에, 같은 비트가 없어 결과값이 0000(0)이 된다.
Reference
C 프로그래밍 (김형근, 곽덕훈, 정재화 공저)
C 프로그래밍 강의 (방송통신대 - 이병래)
Comments