1. 비트 연산자, 비트 이동 연산자란?
- 비트를 연산할 때 쓰이는 연산자. 정수나, 정수로 변환 가능한 타입에서만 가능(실수나 포인터는 연산 불가)
- 비트 : 바이트보다 더 작은 단위이며, 2진수(0, 1)를 저장. 2진수 개념이기에 생소할 수 있음.
- 비트 단위로 계산하기 때문에, 일반 사칙연산보다 훨씬 속도가 빠름.
- 메모리 공간의 효율성을 높이고, 연산의 수를 줄일 수 있음.
- &(AND), |(OR), ^(XOR), ~(NOT),<<(지정한 수만큼 비트 열을 왼쪽으로 이동), >>(오른쪽 이동)
- 비트에 대한 연산이기 때문에, 수학적으로 이해하고자 하면 복잡해질 수 있다. 나중에 어떤 쓸모가 있을지만 고민..
- 추후에 A집단과 B집단을 비교하는 문제 등에서 사용하면 좋지 않을까...?
비트 연산자 | & | | | ^ | ~(피연산자 1개) | <<2 | >>2 | ||
유사한 논리 연산자 | && | || | (없음) | !(피연산자 1개) | (없음) | (없음) | ||
수A의 비트 | 수B의 비트 |
결과값 | ||||||
0 | 0 | 0 | 0 | 0 | A = 1, B=1 | |||
0 | 1 | 0 | 1 | 1 | A = 1, B=0 | |||
1 | 0 | 0 | 1 | 0 | A = 0, B=1 | |||
1 | 1 | 1 | 1 | 1 | A = 0, B=0 |
1) & 연산자 : AND연산자. 1에 대해 교집합적 특성.
- a & b : 두 개의 비트가 모두 1일 때만 1 반환.(논리곱&& 연산과 유사)
- cf1) &(단항 연산자) = 피연산자 1개 : 주소 값 연산자. 주소 값 반환.
- cf2) &&연산자는 논리 연산자(True, False반환)
6 = | & | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
8 = | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | = 0 |
6 = | & | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
13 = | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | ||
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | = 4 |
#include <stdio.h>
int main()
{
unsigned char a = 6; // 0000 0110
unsigned char b = 8; // 0000 1000
unsigned char c = a & b;
printf("6와 8의 AND 연산 값 : %d\n", c); //0000 0000 즉, 0 출력
a = 6; // 0000 0110
b = 13; // 0000 1101
c = a & b;
printf("6과 13의 AND 연산 값 : %d", c); // 0000 0100 즉, 4 출력
return 0;
}
- cf1) char을 써준 이유 : char = 8비트. 주로 사용하는 int는 32비트. 즉 앞에 무수한 0 을 작성해주어야 하기에..
굳이 작은 수로 충분한 비트 연산자를 공부하기 위해서 32비트를 할당할 필요는 없다.
- cf2) unsigned를 사용한 이유 : 음수의 경우 MSB가 1이면 보수 연산 예외를 주지 않기 위함.
*MSB(Most Significant Bit)란, 비트의 맨 앞자리로, 1일 경우 해당 수가 음수임을 나타낸다.
** 보수 연산에 대해서는 추후에 업데이트 예정.
2) | 연산자 : OR연산자. 1에 대해 합집합적 특성.
- a | b : 두 개의 비트 중 하나라도 1이면 1 반환.(논리합|| 연산과 유사)
6 = | | | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
8 = | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ||
0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | = 14 |
6 = | | | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
13 = | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | ||
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | = 15 |
#include <stdio.h>
int main(void)
{
unsigned char a = 6; // 0000 0110
unsigned char b = 8; // 0000 1000
unsigned char c = a | b;
printf("4와 8의 OR 연산 값 : %d\n", c); // 0000 1110 즉, 14
a = 6; // 0000 0110
b = 13; // 0000 1101
c = a | b;
printf("6과 13의 OR 연산 값 : %d", c);\ // 0000 11111 즉, 15
return 0;
}
3) ^ 연산자 : XOR 연산자. a와 b의 대칭 차집합 개념.(ab합집합 - ab 교집합)
- a ^ b = a | b - a & b. 즉, 두개의 비트가 서로 다를 때 1을, 같을 때 0을 반환.
6 = | ^ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
8 = | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ||
0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | = 14 |
6 = | ^ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
13 = | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | ||
0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | = 11 |
#include <stdio.h>
int main(void)
{
unsigned char a = 6; // 0000 0110
unsigned char b = 8; // 0000 1000
unsigned char c = a ^ b;
printf("6과 8의 XOR 연산 값 : %d\n", c); // 0000 1110 즉, 14
a = 6; // 0000 0110
b = 13; // 0000 1101
c = a ^ b;
printf("6과 13의 XOR 연산 값 : %d", c); // 0000 1011 즉, 11
return 0;
}
4) ~ 연산자 : NOT 연산자. 부정(반전)
- ~a : 모든 비트를 반대로.(0->1, 1->0, 논리 연산자! 과 유사).
(1) unsigned char을 이용할 시 :
6 | ! | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | |
1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | = 249 |
13 = | ^ | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | |
1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | = 242 |
#include <stdio.h>
int main(void)
{
unsigned char a = 6; // 0000 0110
unsigned char b = ~a; // 1111 1001 즉, 251
unsigned char c = 13; // 0000 1101
unsigned char d = ~c; // 1111 0010 즉, 242
printf("6과 13의 NOT 연산 값 : %d, %d\n", b, d);
return 0;
}
(2) signed char을 이용할 시 : 보수 연산의 개념이 필요하기에 추후에 별도로 업데이트하도록 한다.
5) >>, << : 비트 이동 연산자.
- 지정한 횟수대로 비트의 자리를 이동시킨다. 튀어나가는 값은 삭제, 빈자리는 0으로 대체한다(signed 예외).
(1) << 연산자(쉬프트, 시프트)
- << n : 비트를 왼쪽으로 n 번만큼 이동.
- <<1 : 2배, <<2 : 4배, <<3 : 8배.,
- 즉 원래 수에 2의 n승을 곱해주는것 이지만, 비트로 연산하기에 훨씬 빠르다.
- int는 32비트(32자리), char은 8자리이기 때문에, 같은 수라도 각 자료형마다 잘리는 값의 크기가 다를 수 있다.
cf) signed형의 경우 MSB로 비트가 이동시 보수 연산을 한다.
#include <stdio.h>
int main(void)
{
char a = 1 << 8; // 0000 0001
int b = 1 << 8; // 0000 0000 0000 0000 0000 0000 0000 0001
printf("(char) 1 << 8 : %d\n", a); // 0000 0000 즉, 0 출력
printf("(int) 1 << 8 : %d\n", b);
// 0000 0000 0000 0000 0000 0001 0000 0000 즉, 256 출력
unsigned char c = 1 << 7; // 1000 0000 즉, 128 츨력
char d = 1 << 7; // ??? 보수연산 값 출력.
printf("(unsigned) 1 << 7 : %d\n", c);
printf("(signed) 1 << 7 : %d\n", d);
return 0;
}
(2) >>연산자(쉬프트, 시프트)
- >> n : 비트를 오른쪽으로 n번만큼 이동.
- >>1 : (2의-1승0, >>2 : (2의 -2승), >>3 : (2의 -3승).,
- 즉 원래 수에 2의 n승을 나눠주는 것이지만, 비트로 연산하기에 훨씬 빠르다.
- MSB의 경우 음수일 때 unsigned의 경우와 signed의 경우 처리방법이 다르다.
(CPU에 따라, 음수를 유지하기 위해 빈자리에 0 대신 1을 채우는 종류와, 0을 채우는 종류가 있다.)
#include <stdio.h>
int main(void){
unsigned char a = 4 >> 1; // 0000 0100
unsigned char b = 8 >> 2; // 0000 1000
printf("4 >> 1 : %d\n", a);// 0000 0010 즉, 2
printf("8 >> 2 : %d\n", b);// 0000 0010 즉, 2
a = 14 >> 3; // 0000 1110
b = 16 >> 4; // 0001 0000
printf("14 >> 3 : %d\n", a);//0000 0001 즉, 1
printf("16 >> 4 : %d\n", b);//0000 0001 즉, 1
char c = -16 >> 2; // 1111 0000
printf("-16 >> 2 : %d\n", c);//1111 1100 즉. -4(빈자리에 1을 채우는 CPU 가정)
}
'C' 카테고리의 다른 글
[C언어_활용] 누적 계산기(for, while문 활용) (0) | 2021.12.09 |
---|---|
[C언어] 반복문(for, while, do while) (0) | 2021.12.09 |
[C언어] 비교 연산자(==,!=,<>,<=>)/ 논리 연산자(&&,||), 복합 대입 연산자 (0) | 2021.12.08 |
[C언어] 증감 연산자(++,--)/ 전위 연산자, 후위 연산자 (0) | 2021.12.08 |
[C언어] 기본 연산자( + , - , * , / , % ) (0) | 2021.12.08 |
야나의 코딩 일기장 :) #코딩블로그 #기술블로그 #코딩 #조금씩,꾸준히
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!