[C언어] 비트 연산자 - 코딩도장
[코딩도장] Unit 23 ~ 25
1. 비트 연산자 사용하기
1. 비트 연산자
비트 연산자는 바이트 단위보다 더 작은 비트 단위로 연산하는 연산자이다
비트 연산은 모든 연산을 2진수로 계산한다
비트로 옵션을 설정할 때 주로 사용하며 저장공간을 아낄 수 있다는 장점이 있다
이런 방식을 플래그( flag )라고 한다
& 연산자
& 연산자는 비트 AND 이므로 두 비트가 모두 1일 때 1이 된다
1 1 → 1
0 1 → 0
0 1 → 0
0 0 → 0
| 연산자
| 연산자는 비트 OR 이므로 둘 중 하나의 비트가 1일 때 1이 된다
1 1 → 1
0 1 → 1
1 0 → 1
0 0 → 0
^ 연산자
^ 연산자는 비트 XOR 이므로 두 비트가 다를 때 1이다
1 1 → 0
0 1 → 1
1 0 → 1
0 0 → 0
~ 연산자
~ 연산자는 비트 NOT 연산자이다
0은 1로 1은 0으로 바꾸며 "비트를 뒤집는다" 또는 "비트 반전"이라고 말한다
0 → 1
1 → 0
<<, >> 시프트 연산자
지정한 횟수대로 비트를 이동시키고 모자란 부분은 0으로 채운다
변수 << 이동할 비트 수
변수 >> 이동할 비트 수
형식으로 사용한다
2. 비트 연산자로 플래그 처리하기
플래그는 적은 공간에 정보를 저장해야 하고
빠른 속도가 필요할 때 사용한다
CPU는 내부 저장 공간이 작기 때문에 대부분의 정보를 비트로 저장한다
리눅스 커널의 소스 코드나 하드웨어에서 사용한다
4Byte = 32Bit, 32개의 상태 처리 가능
0100 0001 // 두 번째 비트와 여덟 번째 비트가 켜진 상태(on)
마스크(mask)는 비트의 플래그를 조작하거나 검사할 때 사용하는 숫자를 말한다
특정 비트를 키는 법
flag |= 마스크
OR연산의 특성을 이용한다
0 | 1 → 1 꺼짐 → 켜짐
1 | 1 → 1 켜짐 → 켜짐
특정 비트를 끄는 법
flag &= ~마스크
마스크 값을 ~ 연산자로 뒤집고
&= 연산을 통해 비트를 끈다
unsigned char flag = 7; // 7: 0000 0111
flag &= ~2;
마스크 값인 2의 비트를 뒤집으면
0000 0010
_________ ~
1111 1101
플래그와 마스크를 AND 연산하면
이렇게 원하는 비트를 끌 수 있다
토글(toggle) 하는 법
비트가 켜져있다면 끄고 꺼져있다면 키는 방법
XOR연산의 특성을 이용한다
두 비트가 다르면 1 같으면 0이 된다
1 ^ 1 → 0 켜짐 → 꺼짐
0 ^ 1 → 1 꺼짐 → 켜짐
1 ^ 0 → 1 켜짐 → 켜짐
0 ^ 0 → 0 꺼짐 → 꺼짐
flag = 7 mask = 2 를 토글하면
0000 0101 이 된다
2. 심사문제
23.8 비트 논리 연산자 사용하기
표준 입력으로 두 정수(unsigned int)가 입력됩니다. 입력된 두 정수의 비트 연산 결과를 각 줄에 출력하는 프로그램을 만드세요(scanf 함수 호출 전에 문자열을 출력하면 안 됩니다).
- num1과 num2을 비트 XOR 연산
- num1과 num2을 비트 OR 연산
- num1과 num2를 비트 AND 연산
- num1을 비트 NOT 연산
출력 결과는 서식 지정자 %u를 사용하세요.
정답에는 C 언어 컴파일러에서 정상적으로 컴파일되는 전체 코드를 입력해야 합니다.
#include <stdio.h>
int main() {
unsigned int num1, num2;
scanf("%u %u", &num1, &num2);
printf("%u\n", num1 ^ num2);
printf("%u\n", num1 | num2);
printf("%u\n", num1 & num2);
printf("%u\n", ~ num1);
return 0;
}
23.9 시프트 연산자 사용하기
표준 입력으로 정수가 입력됩니다. 입력된 정수를 왼쪽으로 20번, 오른쪽으로 4번 시프트 연산하여 결과를 출력하는 프로그램을 만드세요(scanf 함수 호출 전에 문자열을 출력하면 안 됩니다). 단, 정수형 변수는 unsigned long long으로 선언하고 출력 결과는 서식 지정자 %llu를 사용하세요.
정답에는 C 언어 컴파일러에서 정상적으로 컴파일되는 전체 코드를 입력해야 합니다.
#include <stdio.h>
int main() {
unsigned long long int num1;
scanf("%llu", &num1);
num1 <<= 20;
num1 >>= 4;
printf("%llu", num1);
return 0;
}
24.7 시프트 연산과 플래그 활용하기
표준 입력으로 두 정수가 입력됩니다(입력 값의 범위는 0~255). 플래그에 다음과 같은 연산을 하여 결과가 출력되게 만드세요. 정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.
- num1의 비트를 왼쪽으로 3번 이동한 값으로 flag의 비트 켜기
- num2의 비트를 오른쪽으로 2번 이동한 값으로 flag의 비트 끄기
- flag의 첫 번째 비트 토글하기
#define __USE_MINGW_ANSI_STDIO 1 // Dev-C++(MinGW)에서 %hhu를 사용하기 위한 설정
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
unsigned char flag = 16;
unsigned char num1, num2;
scanf("%hhu %hhu", &num1, &num2);
___________________
___________________
___________________
printf("%u\n", flag);
return 0;
}
정답
flag |= (num1 <<= 3);
flag &= ~(num2 >>= 2);
flag ^= (1 << 7);
16 : 0001 0000
num1 <<= 3 의 값으로 비트 켜기
비트를 키려면 |= 연산자를 사용해야 한다
flag |= (num1 <<= 3)
num2 >>= 2 의 값으로 비트 끄기
비트를 끄려면 ~ 연산자를 이용해 마스크를 뒤집고 &= 연산자를 사용한다
flag &= ~(num2 >>= 2)
flag 의 첫번째 비트 토글하기
비트를 토글하기 위해서는 ^= 연산자를 사용한다
1은 8번째 비트이기 때문에 왼쪽으로 7번 이동시킨다
flag ^= (1 << 7)
25.6 괄호 사용하기
표준 입력으로 세 정수가 입력됩니다. 다음 순서대로 연산한 뒤 결과가 출력되게 만드세요.
- num1과 num2를 더하기
- 1번 결과에 10을 곱하기
- 2번 결과에서 num3을 빼기
정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num1;
int num2;
int num3;
scanf("%d %d %d", &num1, &num2, &num3);
printf("%d\n", _________________________);
return 0;
}
정답
((num1 + num2) * 10) - num3