비트 연산자는 정수를 2진수 비트 줄로 보고 같은 자리의 비트끼리 계산합니다. AND &·OR |·XOR ^·NOT ~과, 비트를 옆으로 옮기는 시프트 <<·>>가 있습니다. 컴퓨터는 음수를 2의 보수로 담아 ~5가 −6이 되고, 서브넷 마스크(AND)와 오류 검출(XOR)도 이 연산으로 셈합니다. 아래 그림은 두 비트 줄을 위아래로 놓고 자리마다 결과 비트를 구한 뒤, 비트를 뒤집고 1을 더해 음수를 만드는 모습입니다.
1AND·OR·XOR — 같은 자리끼리
두 수를 2진수로 쓰고 오른쪽 끝을 맞춘 뒤, 자리마다 따로 계산합니다. 12는 1100, 10은 1010입니다.
| 연산 | 결과 비트가 1인 때 | 12와 10 |
|---|---|---|
AND & | 둘 다 1 | 1000 = 8 |
OR | | 하나라도 1 | 1110 = 14 |
XOR ^ | 서로 다를 때 | 0110 = 6 |
AND는 서브넷과 CIDR의 마스크 계산에, XOR는 오류 검출과 정정의 CRC와 이진 탐색과 해싱의 폴딩법에 쓰입니다. 세 레슨은 뒤 단원에서 나옵니다.
&&·||는 참·거짓을 보는 논리 연산자라 다릅니다. 6 && 1은 둘 다 0이 아니어서 1이지만, 6 & 1은 0110과 0001에 함께 1인 자리가 없어 0입니다.
2시프트 — 비트를 옮긴다
x << n은 비트를 왼쪽으로 n칸 옮기고 오른쪽 빈자리를 0으로 채워, x에 2ⁿ을 곱한 값이 됩니다(양수이고 넘치지 않을 때).
x >> n은 오른쪽으로 n칸 옮기며 밀려난 비트를 버려, 양수에서는 x를 2ⁿ으로 나눈 몫입니다.
12 << 1은 24, 12 >> 2는 3이고, 13 >> 2도 3입니다. C는 음수를 오른쪽으로 옮긴 결과를 컴파일러마다 다르게 둘 수 있습니다.
32의 보수와 NOT
비트를 모두 뒤집은 것을 1의 보수, 1의 보수에 1을 더한 것을 2의 보수라 합니다. 컴퓨터는 음수 −x를 x의 2의 보수로 담고, 맨 왼쪽 비트를 부호로 읽습니다(0이면 양수, 1이면 음수).
| 8비트 | 비트 | 값 |
|---|---|---|
| 5 | 00000101 | 5 |
| 5의 1의 보수 | 11111010 | −6 |
| 5의 2의 보수 | 11111011 | −5 |
~는 비트를 뒤집기만 하는 1의 보수라, ~5는 −5보다 1 작은 −6입니다. 어떤 수든 ~x는 −x − 1입니다.
맨 왼쪽이 1인 비트 줄은 다시 뒤집고 1을 더한 크기에 −를 붙여 읽습니다(11111011 → 00000101 → −5). 8비트에는 −128(10000000)부터 127(01111111)까지 담깁니다.
C의 int는 4바이트, 곧 32비트지만, −128~127인 값은 앞쪽 24비트가 맨 왼쪽 비트와 같아 8비트로 셈한 값과 같습니다.
예제
16진수 비트 연산
16진수는 한 자리씩 4비트로 풀어 계산합니다.
#include <stdio.h>
int main(void) {
int a = 0x2C;
int b = 0x0F;
printf("%d %d\n",
a & b, a | b);
printf("%x %d\n", a ^ b, ~a);
return 0;
}
무엇이 찍힐까요? 답을 정한 뒤 펼쳐 보세요.
실행 결과 보기
12 47
23 -45| 식 | 16진수 | 2진수 | 10진수 |
|---|---|---|---|
| a | 2C | 0010 1100 | 44 |
| b | 0F | 0000 1111 | 15 |
| a & b | 0C | 0000 1100 | 12 |
| a | b | 2F | 0010 1111 | 47 |
| a ^ b | 23 | 0010 0011 | 35 |
| ~a | — | 1101 0011 | −45 |
b의 아래 네 비트가 모두 1이라, a & b는 a의 아래 네 비트만 남기고 a ^ b는 그 네 비트를 뒤집습니다. 둘째 줄의 %x는 35를 16진수 23으로 찍습니다.
같은 코드를 Java·Python으로
| C | Java | Python | |
|---|---|---|---|
^ | XOR | XOR | XOR — 거듭제곱은 ** |
음수를 >>로 | 컴파일러마다 다를 수 있음 | 부호 비트로 채움 | 부호 비트로 채움 |
>>> | 없음 | 0으로 채우는 시프트 | 없음 |
| 정수의 크기 | int 32비트 | int 32비트 | 크기 제한 없음 |
세 언어 모두 ~5는 −6입니다.
시험 포인트
- 필기: 비트 연산의 결과를 구합니다 — AND는 둘 다 1, OR는 하나라도 1, XOR는 다를 때 1입니다. 양수에서
<< n은 2ⁿ을 곱한 값(넘치지 않을 때),>> n은 2ⁿ으로 나눈 몫입니다. 2의 보수는 1의 보수에 1을 더한 것이고, 8비트 범위는 −128~127,~x는 −x − 1입니다. - 실기: 출력을 그대로 씁니다(16진수 비트 연산 출제 주제). 16진수는 한 자리를 4비트로 풀어 계산한 뒤 다시 묶고,
%x와%d가운데 무엇으로 찍는지 봅니다. 이름은 1의 보수(1's Complement)·2의 보수(2's Complement)로 씁니다.
확인 문제
1. 8비트 2의 보수로 나타낼 수 있는 정수의 범위를 고르세요.
- ① 0 ~ 255
- ② −127 ~ 127
- ③ −128 ~ 127
- ④ −255 ~ 255
정답
③입니다. 맨 왼쪽 비트가 0인 128가지가 0~127, 1인 128가지가 −128~−1입니다. 가장 작은 수는 10000000인 −128입니다.
- ① 부호 없이 여덟 비트를 모두 크기로 읽은 범위입니다.
- ② 1의 보수로 담을 때의 범위입니다. 1의 보수는 00000000과 11111111이 둘 다 0이라 하나가 줄어듭니다.
- ④ 8비트로는 256가지만 나타냅니다. 이 범위는 511가지입니다.
2. 그림의 10을 6으로 바꿨습니다. 12 & 6, 12 | 6, 12 ^ 6의 값을 차례로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.
정답
받는 답: 4 · 14 · 10
12는 1100, 6은 0110입니다. 둘 다 1인 자리는 4의 자리뿐이라 AND는 0100 = 4, OR는 1110 = 14, XOR는 둘이 다른 자리만 1이라 1010 = 10입니다.
- 틀리는 꼴 XOR 14: OR와 섞었습니다. 둘 다 1인 4의 자리는 XOR에서 0입니다.
- 틀리는 꼴 AND 0: 6을 0110이 아닌 다른 비트로 풀었습니다. 6은 4 + 2입니다.
3. −12를 8비트 2의 보수로 만드는 표입니다. (가)~(다)를 채우세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.
| 단계 | 8비트 |
|---|---|
| 12 | 00001100 |
| 12의 1의 보수 | (가) |
| 12의 2의 보수 | (나) |
~12의 값은 (다)입니다.
정답
받는 답: (가) 11110011 · (나) 11110100 · (다) −13
비트를 모두 뒤집으면 11110011이고, 1을 더한 11110100이 −12입니다. ~12는 뒤집기만 한 1의 보수라 −12 − 1 = −13입니다.
- 틀리는 꼴 (가)에 11110100: 뒤집기와 1 더하기를 한 번에 했습니다. (가)는 뒤집기만 합니다.
- 틀리는 꼴 (다)에 −12:
~가 2의 보수를 만든다고 봤습니다.~는 1의 보수라 1이 더 작습니다.
4. 다음 코드의 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.
#include <stdio.h>
int main(void) {
int x = 0x5A;
int m = 1 << 3;
printf("%d\n", (x & m) != 0);
printf("%x %d\n",
x >> 4, x ^ 0xFF);
return 0;
}
정답
받는 답:
1
5 1650x5A는 0101 1010이고, 1 << 3은 1을 세 칸 옮긴 0000 1000 = 8입니다. x & m은 8의 자리가 1이라 8이고, 0이 아니니 != 비교가 참 1입니다.
x >> 4는 아래 네 비트를 버려 0101 = 5, x ^ 0xFF는 여덟 비트를 모두 뒤집어 1010 0101 = 165입니다.
- 틀리는 꼴 첫 줄
8:x & m의 값을 찍는다고 봤습니다. 찍는 것은!=비교의 결과 1입니다. - 틀리는 꼴 둘째 줄
5 -91:^ 0xFF를~와 같다고 봤습니다.0xFF는 아래 여덟 비트만 1이라 앞쪽 비트는 그대로 0입니다.
5. 음수를 담는 두 꼴 가운데 (가)·(나)에 맞는 이름을 한글 이름과 영문으로 함께 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.
- (가) 양수의 비트를 모두 뒤집기만 한 꼴입니다. C의
~연산이 이 꼴을 만듭니다. - (나) (가)에 1을 더한 꼴입니다. 컴퓨터가 int의 음수를 이 꼴로 담습니다.
정답
받는 답: (가) 1의 보수(1's Complement) · (나) 2의 보수(2's Complement)
(가)의 실마리는 '뒤집기만', (나)는 '뒤집고 1을 더함'입니다.
- 틀리는 꼴 2의 보수 — (가)에: 뒤집은 뒤 1을 더해야 2의 보수입니다.
~5가 −5가 아니라 −6인 까닭입니다. - 틀리는 꼴 XOR — (가)에: 두 수의 자리를 견주는 연산의 이름입니다. 한 수를 뒤집는 것은 NOT(
~)이고, 그 결과가 1의 보수입니다.
처음이라면: C 언어 과목(준비 중)의 '비트 연산' 레슨에서 같은 규칙을 처음부터 천천히 봅니다.