본 글은 이재범님의 모두의 코드 강좌를 정리합니다.
비트 즉 0과 1로 연산한다. 8bit를 묶어 1Byte로 표현한다. 1바이트 범위는 0부터 11111111b 십진수로 0~255 이다.
&, |, ^, << >>, ~ 연산자가 있다.
1001
&0011
⏬
1 & 1 = 1
1 & 0 = 0
0 & 0 = 0
0 & 1 = 0
각 자리수 끼리 연산한다. 1 & 1 = 1 이지만 나머지는 0을 연산한다.
만약 1111100 과 11을 AND 연산한다면 아래와 같이 11 앞에 0을 추가해 자리수를 맞춘다.
1111100
& 0000011
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0
1 과 0 중 하나만이라도 1이면 1이 된다.
1 ^ 1 = 0
0 ^ 1 = 1
1 ^ 0 = 1
0 ^ 0 = 0
두 수가 달라야 1이 된다.
~ 1001
⏬
>>> 0110
0을 1로 1을 0으로 바꿔주는 연산이다.
1 0 1 0 1 1
↙↙↙↙↙↙
>>> 1 0 1 0 1 1 0
비트를 왼쪽으로 쉬프트 시킨다. 101011을 왼쪽으로 1 칸 옮기면 01011 이 되고 자리수를 맞추기 위해 0이 새로와 010110 이 된다.
쉬프트된 숫자가 갈 자리가 없다면 버리므로 첫번째 1
은 버린다.
뒤에서 새로 채워지는 자리는 무조건 0으로 채운다.
11100010
>>> 11111100
오른쪽으로 쉬프트한다. 쉬프트 된 숫자가 갈 자리가 없다면 버려진다.
이 때 맨 왼쪽에 있었던 수가 채워진다. # 위 예시에선 1
11100010 >> 3 = 11111100
00011001 >> 3 = 00000011
11100010
을 오른쪽으로 3칸 옮기면 11100
이 된다. 빈 자리는 맨 왼쪽에 있던 숫자
여기서는 1
로 채운다. 따라서 빈 자리 3칸을 111
로 채워 11111100
이 된다.
비트 연산은 암호 분야에서 많이 쓰이며 쉬프트 연산도 유용하게 쓰일 때가 있다.
#include <stdio.h>
int main()
{
int a = 0xAF; // 16진수 이므로 2진수로 변환하면 '10101111' 이다.
int b = 0xB5; // 16진수 이므로 2진수로 변환하면 '10110101' 이다.
printf("%x \n", a & b); // a & b = 10100101
printf("%x \n", a | b); // a | b = 10111111
printf("%x \n", a ^ b); // a ^ b = 00011010
printf("%x \n", ~a); // ~a = 1....1 01010000
printf("%x \n", a << 2); // a << 2 = 1010111100
printf("%x \n", b >> 3); // b >> 3 = 00010110
return 0;
}
printf("%x \n", ~a);
, printf("%x \n", a << 2);
, printf("%x \n", b >> 3);
이 3개의 코드를 자세히 얘기해보자.
int
의 Size는 4bytes다. int
는 데이터 하나를 저장하기 위해 메모리상의 4 바이트 즉 32 비트를 사용한다. # 1Bytes = 8bit
비트 하나는 0과 1을 나타낸다. # 비트 한 개가 2진수의 한 자리를 표현함
int
는 32 비트를 표현하고 비트 한 개는 2진수의 한 자리를 표현하므로 int
는 32 자리의 2진수다.
int a = 1
은 컴퓨터에게 a = 00000000 00000000 00000000 00000001
이 저장되는 것과 같다.
그래서 int a = 0xAF
은 컴퓨터에게 a = 00000000 00000000 00000000 10101111
저장해줘란 의미다. # 10101111 앞에 0이 24개 있다
printf("%x \n", ~a);
이 코드의 결과는 ~a
를 반전시킨 값 a = 11111111 11111111 11111111 01010000
, 16진수로는 0xFFFFFF50
이다.
printf("%x \n", a << 2);
이 코드는 a = 00000000 00000000 00000000 10101111
<< 2 결과 왼쪽으로 2칸 움직이고 뒤에 00
이 채워져 a = 00000000 00000000 00000010 10111100
, 16진수로 0x2BC가 된다.
printf("%x \n", b >> 3);
이 코드는 b = 00000000 00000000 00000000 10110101
>> 3 결과 오른쪽으로 3칸 움직이고 뒤에 000
이 채워져 b = 00000000 00000000 00000000 00010110
, 16진수로 0x16이 왼다.
컴퓨터에는 연산할 때 우선순위와 연산방향이 있다. 아래 그림을 보면 () 가 1순위다.
a = b + c + d + e;
+, -
는 제 3 우선순위이며 왼쪽부터 연산해야 한다. 따라서 위 코드는 아래와 같이 연산된다.
a = b = c = d = 3;
만약 대입 연산자가 오른쪽 우선 연산이 아니라 왼쪽 우선이라면 어떤 결과가 나올까? # 대입 연산자는 우선순위 14번 = 복합대입을 뜻한다.
a = b; // 처리 1번
b = c; // 처리 2번
c = d; // 처리 3번
d = 3; // 처리 4번
a
, b
, c
엔 정의되지 않은 변수가 저장되려 해 에러가 발생할 것이다.
하지만 대입 연산자는 아래와 같이 오른쪽부터 연산이 시작된다.
javascript, python은 변수 여러 개의 생성과 초기화를 한번에 할 수 있지만
C 는 여러 개의 생성과 초기화를 한번에 할 수 없다. 그래서 변수 여러 개 생성 후 초기화를 해준다.
변수 한 개는 생성과 초기화가 동시에 된다.
# include <stdio.h>
int main()
{
int a, b, c, d;
a = b = c = d = 3;
printf("%d \n", a);
return 0;
}