본문으로 건너뛰기

비트 연산과 2의 보수

정보처리기사 목차프로그래밍 기초레슨 135 / 233

목차

비트 연산자는 정수를 2진수 비트 줄로 보고 같은 자리의 비트끼리 계산합니다. AND &·OR |·XOR ^·NOT ~과, 비트를 옆으로 옮기는 시프트 <<·>>가 있습니다. 컴퓨터는 음수를 2의 보수로 담아 ~5가 −6이 되고, 서브넷 마스크(AND)와 오류 검출(XOR)도 이 연산으로 셈합니다. 아래 그림은 두 비트 줄을 위아래로 놓고 자리마다 결과 비트를 구한 뒤, 비트를 뒤집고 1을 더해 음수를 만드는 모습입니다.

9단계 중 1단계. AND — 둘 다 1. int 32비트 가운데 오른쪽 8비트. 비트 연산은 두 수를 2진수로 놓고 같은 자리끼리 계산합니다. AND(&)는 두 비트가 모두 1인 자리만 1이라 12 & 10은 8입니다.

1AND·OR·XOR — 같은 자리끼리

두 수를 2진수로 쓰고 오른쪽 끝을 맞춘 뒤, 자리마다 따로 계산합니다. 12는 1100, 10은 1010입니다.

연산결과 비트가 1인 때12와 10
AND &둘 다 11000 = 8
OR |하나라도 11110 = 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비트비트값
5000001015
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진수
a2C0010 110044
b0F0000 111115
a & b0C0000 110012
a | b2F0010 111147
a ^ b230010 001135
~a—1101 0011−45

b의 아래 네 비트가 모두 1이라, a & b는 a의 아래 네 비트만 남기고 a ^ b는 그 네 비트를 뒤집습니다. 둘째 줄의 %x는 35를 16진수 23으로 찍습니다.

같은 코드를 Java·Python으로

CJavaPython
^XORXORXOR — 거듭제곱은 **
음수를 >>로컴파일러마다 다를 수 있음부호 비트로 채움부호 비트로 채움
>>>없음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비트
1200001100
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 165

0x5A는 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 언어 과목(준비 중)의 '비트 연산' 레슨에서 같은 규칙을 처음부터 천천히 봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

정보처리기사 목차로