비트 연산자
1. 비트 연산자의 종류
& : 비트 AND
| : 비트 OR
^ : 비트 XOR
~ : 비트 NOT
<< : 비트를 왼쪽으로 시프트
>> : 비트를 오른쪽으로 시프트
비트연산자는 비트로 옵션을 설정할 때 주로 사용. 이런방식을 FLAG라고 한다.
2. AND / OR / XOR
#include <stdio.h>
void main() {
unsigned char num1 = 1; // 0000 0001
unsigned char num2 = 3; // 0000 0011
printf("AND : %d\n", num1 & num2); // 0000 0001 : 01과 11을 AND 하면 01이 된다.
printf("OR : %d\n", num1 | num2); // 0000 0011 : 01과 11을 OR하면 11이 된다.
printf("XOR : %d\n", num1 ^ num2); // 0000 0010 : 01과 11을 XOR하면 10이 된다
}
AND 는 두 비트가 모두 1 일때 1을 반환하고, 하나라도 0 일때는 0을 반환한다.
ex ) ( 1 , 1 ) = 1 ( 0, 1 ) = 0 ( 1, 0 ) = 0 ( 0 , 0 ) = 0
OR 는 두 비트가 어느것이라도 1일 때 1을 반환하고, 모두 0일때만 0을 반환하게 된다.
ex) ( 1 , 1 ) = 1 ( 0 , 1 ) = 1 ( 1 , 0 ) = 1 ( 0 , 0 ) = 0
XOR은 두 비트중 하나만 1이여만 1을 반환한다, 모두 0이거나 모두 1일때는 0을 반환하게 된다.
ex) ( 1 , 1 ) = 0 ( 0 , 1 ) = 1 ( 1 , 0 ) = 1 ( 0 , 0 ) = 0
3. NOT
#include <stdio.h>
void main() {
unsigned char num1 = 162; // 1010 0010
unsigned char num2;
num2 = ~num1;
printf("%d\n", num2); //0101 1101
}
NOT은 비트를 뒤집는다, 혹은 비트 반전이라도 이야기한다. 0은 모두 1로 바꾸고 1은 모두 0으로 바꾼다.
4. SHIFT
#include <stdio.h>
void main() {
unsigned char num1 = 3; // 3: 0000 0011
unsigned char num2 = 24; // 24: 0001 1000
printf("%u\n", num1 << 3); // 24: 0001 1000 : num1의 비트 값을 왼쪽으로 3번이동
printf("%u\n", num2 >> 2); // 6: 0000 0110 : num2의 비트 값을 오른쪽으로 2번 이동
}
SHIFT는 비트를 왼쪽(<<), 오른쪽(>>)으로 이동한다.
SHIFT 연산자를 이용하면 왼쪽으로 한번이동할때마다 2의 제곱수만큼 곱해진다.
그렇기에 시프트 연산자는 2의 거듭제곱인 숫자를 빠르게 구할 때 유용하다.
ex) num1 << 3 : 3번 왼쪽으로 이동했으니 원래 있던 수에서 2의 3제곱 만큼 곱해진다. 3 * 8 = 24
오른쪽으로 이동하면 2의 제곱수만큼 나눠진다.
ex) num2 >> 2 : 2번 오른쪽으로 이동했으니 원래 있던 수에서 2의 2제곱만큼 나눠진다. 24 / 4 = 6
( SHIFT 연산을 할때는 부호가 바뀌거나 자신이 의도치 않은 값이 나올 수도 있다. )
SHIFT 연산자가 부호없는 자료형의 비트 첫자리나 마지막 자리가 크기 밖으로 이동하면 그 비트는 사라진다.
부호있는 자료형라면 기본적으로 맨 앞 비트 (0000 0000)가 부호를 결정하는 비트가 된다.
만약 첫자리가 부호 비트가 음수, -125 (1000 0011)일 때 << 5 연산을 하면 어떻게 될까?
뒤 두자리 비트는 오른쪽으로 움직여 사라지고 부호 비트는 5자리 뒤로 이동하면서 그 자리를 1로 채우게 된다.
1000 0011 -> 1100 0001 -> 1110 0000 -> 1111 0000 -> 1111 1000 -> 1111 1100
그러므로 -4(1111 1100)이된다.
그러면 부호 비트가 0인 양수, 67(0100 0011) >> 5 연산을 하면 어떻게 될까?
뒤 두자리 비트는 오른쪽으로 움직여 사라지고 부호 비트는 5자리 뒤로 이동하면서 그 자리르 0 으로 채우게 된다.
0100 0011 -> 0010 0001 -> 00001 0000 -> 0000 1000 -> 0000 0100 -> 0000 0010
그러므로 2(0000 0010)가 된다.
부호 있는 자료형에서 << 2 연산을 해보면 어떻게 될까?
113(0111 0001), -15(1111 0001)
113 >> 2
0111 0001 -> 1110 0010 -> 1100 0100
왼쪽으로 움직인 비트들은 사라지고,
부호비트는 1로 바뀌고 음수로 읽혀지게 되어 -60으로 읽혀진다.
-15 >> 2
1111 0001 -> 1110 0010 -> 1100 0100
왼쪽으로 움직인 비트들은 사라지고,
부호비트는 같고 -60으로 읽혀진다.
5. 비트 연산자로 플래그 처리하기
비트로 적은 공간을 사용하여 빠른 속도를 내게 해준다.
비트가 1이면 ON, 0이면 OFF를 나타내고, 1바이트당 총 8개의 상태를 저장할 수 있다.
5-1 . 특정 비트 키기
FLAG |= (?)
ex) flag |= 1; // 0000 0001 비트 OR로 여덟번째 비트를 킨다.
flag |= 2; // 0000 0010 비트 OR로 일곱번째 비트를 킨다.
5-2. 특정 비트 확인하기
if문 안에 사용하며 비트가 있으면 1을 반환하고 없으면 0을 반환한다
FLAG &= (?)
ex) 현재 FLAG는 (0000 0011)
flag &= 1 // 0000 0001 비트가 켜져있는지 확인한다.(1 반환)
flag &= 4 // 0000 0100 비트가 켜져있는지 확인한다.(0 반환)
5-3. 특정 비트 끄기
FLAG &= ~(?)
ex) 현재 FLAG는 (0000 0011)
flag &= ~2 // 0000 0011 & 1111 1101 = 0000 0001 이되므로 2의 비트가 꺼지게된다.
5-4. 특정 비트가 켜져있다면 끄고, 꺼져있다면 키기
FLAG ^= (?)
ex) 현재 FLAG는 (0000 0001)
flag ^= 1 // 0000 0001 ^ 0000 0001 = 0000 0000;
flag ^= 8 // 0000 0000 ^ 0000 1000 = 0000 1000;
'C (예제, 문제)' 카테고리의 다른 글
0321 (0) | 2017.03.21 |
---|---|
0319 (0) | 2017.03.19 |
0318-1 (0) | 2017.03.18 |
소코반 (0) | 2017.03.14 |
[이중 for문]별 찍기 (0) | 2017.03.11 |