C언어 진수 변환과 비트 연산

🔥 매회 출제 (priority 3)

🌱 왜 배우나

사람은 손가락이 열 개라서 숫자를 0~9까지 세다 한 자리를 올린다. 이게 10진수(decimal)다. 컴퓨터는 전기 스위치의 켜짐·꺼짐, 딱 두 상태만 안다. 그래서 0과 1만 쓰는 2진수(binary)가 컴퓨터의 모국어다. 2진수는 금방 길어지니까, 네 자리를 한 글자로 줄인 16진수(hexadecimal)가 따라붙는다. 웹 색상 코드 #FF5733이나 메모리 주소를 16진수로 쓰는 이유다. 진수 변환을 모르면 코드가 출력한 0x1A가 무슨 값인지 읽을 수가 없다.

📖 핵심 개념

진수는 “숫자를 몇 개의 기호로 세는가”를 정하는 약속이다. 10진수는 09, 2진수는 01, 8진수(octal)는 07, 16진수는 09와 A~F를 쓴다.

10진수를 다른 진수로 바꾸는 공식은 한 줄이다. “그 진수의 밑(base)으로 계속 나누고, 나머지를 역순으로 읽는다.” 예를 들어 87을 16진수로 만들면, 87÷16=5 나머지 7, 5÷16=0 나머지 5다. 역순으로 읽으면 “57”. 왜 역순일까. 처음 구한 나머지가 1의 자리, 그 다음이 16의 자리이기 때문이다.

printf의 서식 문자(format specifier)를 쓰면 변환이 더 쉽다. %d는 10진수, %o는 8진수, %x·%X는 16진수다(소문자·대문자).

비트 연산자는 정수를 2진수로 놓고 자릿수(비트)끼리 논리 계산한다. AND(&)는 둘 다 1일 때만 1. OR(|)는 하나만 1이어도 1. XOR(^, exclusive or)는 서로 다를 때만 1. NOT(~)은 0과 1을 뒤집기. 시프트(<<, >>)는 비트를 좌우로 밀어서 곱하기 2, 나누기 2 효과를 낸다.

🔍 시각화

┌─────────── 10진수 87 → 16진수 변환 ───────────┐
│                                                │
│  87 ÷ 16 = 5  나머지 7  → hex[0] = '7'        │
│   5 ÷ 16 = 0  나머지 5  → hex[1] = '5'        │
│                                                │
│  역순 출력: 5  7  →  "57"                      │
└────────────────────────────────────────────────┘

┌─────────── 비트 AND 연산 ─────────────────────┐
│  a = 0x1A  →  0 0 0 1  1 0 1 0  (26)         │
│  b = 0x0F  →  0 0 0 0  1 1 1 1  (15)         │
│  ──────────────────────────────               │
│  a & b     →  0 0 0 0  1 0 1 0  (0A = 10)    │
│  (둘 다 1인 자리만 1)                          │
└───────────────────────────────────────────────┘

┌─────────── 왼쪽 시프트 ───────────────────────┐
│  c = 3     →  0 0 0 0  0 0 1 1               │
│  c << 2    →  0 0 0 0  1 1 0 0  (12 = 3×4)   │
│  (비트가 왼쪽으로 2칸 이동, 빈자리는 0)        │
└───────────────────────────────────────────────┘

↔️ 이웃 개념 구분

  • 진수 변환 vs 비트 연산: 진수 변환은 같은 숫자를 다른 표기법으로 바꾸는 일. 비트 연산은 2진수 자릿수를 직접 조작하는 일.
  • << 시프트 vs * 곱셈: n << kn × 2^k와 결과가 같다. 다만 비트를 미는 전용 연산이라 곱셈보다 빠르다.
  • 0x 접두어 vs %X 서식: 0x1A는 코드에 16진수를 적는 표기. %X는 출력할 때 16진수로 찍는 서식.

🔑 핵심 용어

  • 진수(numeral system): 숫자를 몇 개의 기호로 세느냐를 정하는 방식
  • printf 서식: %d(decimal, 10진수), %o(octal, 8진수), %x/%X(hexadecimal, 16진수)
  • 0x 접두어: 16진수 리터럴(코드에 직접 쓴 값)을 나타냄. 0x1A = 26
  • 0 접두어: 8진수 리터럴을 나타냄. 010 = 8
  • 비트 AND(&): 두 비트 모두 1이면 1, 그 외 0
  • 비트 OR(|): 하나라도 1이면 1
  • 비트 XOR(^, exclusive or): 서로 다르면 1, 같으면 0
  • 비트 NOT(~): 모든 비트를 반전(0→1, 1→0)
  • 왼쪽 시프트(<<): 비트를 왼쪽으로 이동. n << 1은 n × 2
  • 오른쪽 시프트(>>): 비트를 오른쪽으로 이동. n >> 1은 n ÷ 2(몫)

✅ 스스로 가르쳐보기

진수라는 말을 처음 듣는 친구에게 “10진수 200을 16진수로 바꾸는 이야기”를 들려준다면 어떻게 말하시겠어요? 본인만의 비유(예: 동전 바꾸기, 자릿수 올림) 하나를 넣어 한 문장 정의부터 만들어 보세요.

체크포인트:

  • 왜 하필 16으로 나누는지 이유를 말할 수 있는가
  • 나머지가 10 이상일 때 A~F로 바꾸는 이유를 설명할 수 있는가
  • 나머지를 역순으로 읽어야 하는 이유를 말할 수 있는가
  • 200을 직접 계산해 C8이 나오는 과정을 보여줄 수 있는가

🎯 기출 포인트

  • 2025-1회: 10진수 → 16진수 변환 코드 출력 추적 (답: 908). 기출파괴 포인트로 수험생 다수 오답
  • 출제 패턴: while문으로 나머지 연산 반복 → 역순 출력. 진수 변환 원리를 코드로 구현
  • 비트 연산: AND/OR/XOR/시프트 연산 결과 추적. 2진수로 변환 후 비트별 계산
  • 주의: %X는 대문자, %x는 소문자 16진수 출력

🔗 연결 개념