읽는 데 5분
switch를 컴파일했더니 나온 2753205, 숫자 하나에 숨긴 문자 목록
소스 코드에는 문자를 고르는 switch만 있었는데, 컴파일한 결과에는 2753205라는 숫자가 튀어나와요. 어디서 온 숫자일까요. 사람이 보기에 뜻이 없어 보이는 이 상수는, 사실 선택할 문자 목록을 작은 비트 묶음으로 접은 결과예요.
최근 GeekNews에 다시 소개된 Xoranth의 「Switch lowering in GCC」는 이런 변환을 실제 코드와 함께 설명해요. 원문은 2024년 1월 14일 글이에요. 새 GCC 기능 발표가 아니라, 컴파일러가 switch를 어떻게 바꿀 수 있는지 읽는 이야기로 살펴볼게요.
문자마다 한 칸씩 표시해요
원문의 예시는 '0', '2', '4', '5', '7', '9', 'A', 'C', 'E'일 때 같은 함수를 호출하고, 나머지는 기본 분기로 보내요. 이 문자들을 하나씩 비교하는 대신, 가능한 값마다 한 칸을 배정해 해당하면 1, 아니면 0으로 표시할 수 있어요. 이런 집합 표현을 비트셋이라고 해요.
각 문자의 ASCII 코드에서 '0'의 코드인 48을 빼면 다음 위치가 나와요.

비트 위치는 오른쪽 끝을 0번으로 세고, 왼쪽으로 한 칸 갈 때마다 값이 두 배가 돼요. 0번은 1, 1번은 2, 2번은 4예요. 그림에 나온 위치의 값을 모두 더하면 2753205가 돼요. 원문 밖에서 이 합을 다시 계산해 같은 값이 나오는지 확인했어요.
범위를 확인한 뒤 한 비트만 읽어요

원문의 x86 어셈블리는 입력에서 48을 빼고 범위를 검사한 뒤, bt 명령으로 이 상수의 해당 비트를 읽어요. 그 비트가 1이면 함수 쪽으로 분기해요. 문자마다 긴 비교문을 늘어놓는 대신 범위 검사와 비트 조회로 집합에 속하는지 판단하는 셈이에요.
범위 검사는 이 설명에서 빠지면 안 돼요. 비트 위치로 사용할 수 있는 값인지 먼저 확인해야 하거든요. 저는 원문과 같은 0~21의 위치 제한을 둔 판정식을 따로 작성해, 정수 -128부터 255까지의 입력에서 원래 문자 집합과 결과를 비교했어요. 검사한 384개 입력에서 차이는 없었어요. GCC를 실행한 시험이 아니라 이 예시의 집합 표현을 검산한 결과예요.
모든 switch가 이렇게 바뀌지는 않아요
이 방식은 같은 일을 하는 값들을 작은 범위 안에서 묶을 수 있을 때 유용해요. 원문이 보여 주는 다른 switch들은 다른 모습으로 변해요.
- 점프 테이블: 입력값에 대응하는 이동 위치를 표에 담고 찾아가요. 서로 다른 처리를 하는 값들이 촘촘히 모여 있을 때 쓸 수 있어요.
- 비교 트리: 값을 기준으로 범위를 나누며 비교해요. 값 사이가 멀어 큰 표를 만들기 부담스러운 경우에 선택할 수 있어요.
- 혼합: 한
switch안에서도 촘촘한 구간은 표로, 멀리 떨어진 값은 별도 비교로 처리할 수 있어요.

따라서 소스의 case 개수만 보고 기계어 모양을 단정하기는 어려워요. 값의 간격, 같은 처리로 합칠 수 있는 구간, 최적화 설정과 대상 환경이 함께 영향을 줘요. 이 글의 상수는 아홉 문자를 묶은 한 예시이고, 실제 프로그램의 속도 우열은 별도 측정이 필요해요.
확인한 범위
- 기준일: 2026-11-01. 원문 발표일은 2024-01-14예요.
- 읽은 것: Xoranth의 원문과 공개된 어셈블리 및 GCC 코드 해설, GeekNews의 재소개를 읽었어요.
- 직접 확인한 것: 문자별 비트 위치와 상수를 Python으로 다시 계산하고, -128~255 입력 384개에서 범위 검사를 포함한 집합 판정 결과를 대조했어요. 불일치는 없었어요.
- 읽지 못한 것: 현재 GCC 소스 전체와 버전별 변경 이력은 확인하지 않았어요.
- 직접 해보지 못한 것: GCC로 예시를 다시 컴파일하거나 실행 시간을 측정하지 않았어요. 현재 버전에서 같은 어셈블리가 나온다는 주장은 하지 않아요.