진법과 텍스트 인코딩: 개발자를 위한 치트시트
숫자와 텍스트는 컴퓨터 안에서 결국 같은 것, 즉 비트가 됩니다. 하지만 개발자는 사람 친화적 표현과 기계 친화적 표현 사이를 끊임없이 오갑니다 — 16진수 색상 코드, Base64 토큰, URL 이스케이프된 쿼리 문자열. 이 가이드는 매일 마주치는 진법과 인코딩, 그리고 각각이 실제로 무엇을 위한 것인지에 대한 실용 지도입니다.
진법: 같은 값, 다른 옷
'진법(base)'이란 위치 기수법이 다음 자리로 올라가기 전에 사용하는 서로 다른 숫자의 개수일 뿐입니다. 10진법은 0–9를, 2진법은 0과 1을, 8진법은 0–7을, 16진법은 0–9 다음 A–F를 씁니다. 진법이 달라져도 숫자 자체는 변하지 않습니다 — 표기 방식만 바뀝니다. 2진수 11111111, 8진수 377, 10진수 255, 16진수 FF는 모두 완전히 같은 값입니다.
16진수가 프로그래머에게 인기 있는 이유는 한 자리 16진수가 정확히 4비트(니블)에 대응하므로 두 자리 16진수가 정확히 1바이트이기 때문입니다. 덕분에 16진수는 원시 이진 데이터를 간결하고 손실 없이 읽는 방법이 됩니다 — 색상(#FF8800), 메모리 주소, 바이트 덤프를 16진수로 쓰는 이유죠.
진법 간 변환
이 변환들은 순전히 기계적입니다 — 바로 도구가 대신 해 줘야 할 종류의 일이죠 — 하지만 연산의 형태를 알면 결과를 점검하고 코드의 0x, 0o, 0b 접두사가 무엇을 뜻하는지 이해하는 데 도움이 됩니다.
- 2진수 ↔ 16진수: 비트를 오른쪽부터 네 개씩 묶습니다; 4비트 묶음 하나가 16진수 한 자리입니다(1010 1100 = AC).
- 임의 진법 → 10진수: 각 자리 숫자에 자리값(진법의 위치 거듭제곱)을 곱해 더합니다.
- 10진수 → 임의 진법: 진법으로 반복해서 나눕니다; 나머지를 마지막부터 처음 순으로 읽으면 그것이 자릿수입니다.
문자에서 바이트로: UTF-8
텍스트는 인코딩하기 전까지는 바이트가 아닙니다. 문자 집합은 각 문자에 번호('코드 포인트')를 부여하고 — 유니코드가 그 보편적 표준입니다 — 인코딩은 그 번호가 어떻게 바이트가 될지를 정합니다. UTF-8은 웹의 지배적 인코딩입니다: ASCII 문자는 1바이트, 그 외 문자는 2–4바이트를 차지하여, 영어 텍스트는 간결하게 유지하면서 모든 문자 체계와 이모지를 표현합니다.
그래서 문자열의 문자 길이와 바이트 길이가 다를 수 있습니다: 'café'는 네 글자지만 UTF-8로는 다섯 바이트인데, é가 두 바이트를 필요로 하기 때문입니다. 해싱, 크기 제한, 이진 형식은 모두 바이트를 신경 쓰므로 이 구분이 실무에서 중요합니다.
Base64: 안전한 텍스트로서의 바이트
Base64는 반대의 일을 합니다: 임의의 바이트를 64개의 안전한 문자(A–Z, a–z, 0–9, 그리고 +와 /)의 문자열로 바꿉니다. 이메일, JSON, URL, HTML data: URI 등 많은 시스템이 텍스트를 위해 만들어져 원시 이진을 손상시킬 수 있기에 존재합니다. Base64는 텍스트 전용 통로로 이미지나 키를 온전히 실어 나르게 해 줍니다.
비용은 크기입니다: Base64는 3바이트마다 4문자로 인코딩하므로 출력은 입력보다 약 33% 커집니다. 이는 암호화가 아니라 인코딩이며 — 누구나 디코딩할 수 있습니다 — 따라서 전송 중 손상은 막아도 엿보는 눈은 결코 막지 못합니다.
URL과 퍼센트 인코딩
URL에는 자체 규칙이 있습니다. URL에서 특별한 의미를 갖는 문자(공백, &, ?, #, /)는 % 뒤에 그 바이트 값을 16진수로 붙인 '퍼센트 인코딩'으로 표기해야 합니다 — 공백은 %20, 앰퍼샌드는 %26이 됩니다. 이것이 쿼리 문자열이 주소를 깨뜨리지 않고 임의의 텍스트를 실어 나르게 합니다.
퍼센트 인코딩은 문자의 UTF-8 바이트에 대해 작동하며, 이것이 모든 것을 하나로 묶습니다: 텍스트는 코드 포인트가 되고, 코드 포인트는 UTF-8 바이트가 되며, 바이트는 %XX 쌍이 됩니다. 개발자가 부딪히는 인코딩 버그 대부분은 이 계층 중 하나를 다른 것으로 혼동하는 데서 옵니다.