Menu

C 언어 switch 문: case, break, 그리고 폴스루

C의 switch 문이 상수 목록에서 분기 하나를 고르는 방법 - case 레이블, break가 중요한 이유, 의도한 폴스루와 실수로 생긴 폴스루, default, char와 enum으로 분기하기, 그리고 switch가 else-if 사슬보다 나은 순간.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

값 하나, 여러 상수

같은 변수를 상수들과 계속 비교하는 else if 사슬은, C에 전용 문장이 따로 있는 패턴입니다.

if (choice == 1)      { /* ... */ }
else if (choice == 2) { /* ... */ }
else if (choice == 3) { /* ... */ }
else                  { /* ... */ }

switch는 그것을 더 직접적으로 말합니다. 식을 한 번 평가하고 일치하는 레이블로 곧장 점프합니다.

choice를 바꿔 다시 실행해 보세요. 이 구조는 유효한 값의 집합을 한눈에 보이게 만들어 주고, 여기서 switch를 선호하는 진짜 이유가 그것입니다.

문법과 case 레이블의 규칙

switch (정수식) {
    case 상수_1:
        문장들
        break;
    case 상수_2:
        문장들
        break;
    default:
        문장들
        break;
}

C가 강제하는 제약이 넷 있습니다.

  • switch 식은 정수 타입이어야 합니다. int, char, short, long, 또는 enum입니다. float도, double도, 문자열도 안 됩니다.
  • 모든 case 레이블은 컴파일 타임에 알 수 있는 상수 식이어야 합니다. n이 변수일 때 case n:은 오류이고, case 3 + 4:case MAX:(#define 또는 enum 상수)는 괜찮습니다.
  • 두 case가 같은 값을 가질 수 없습니다. 중복은 컴파일 오류이고, 작지만 진짜 안전망입니다.
  • case는 범위를 표현할 수 없습니다. case 1 ... 5:는 GCC 확장이지 표준 C가 아닙니다. 범위에는 if를 쓰세요.

default는 선택 사항이고 블록 안 어디에나 놓을 수 있지만, 마지막에 두는 것이 거의 보편적인 관례입니다. default가 없으면 일치하지 않는 값은 그냥 switch 전체를 건너뜁니다.

break: 선택 사항이 아닌 이유

C의 switch에서 가장 놀라운 점 하나는, case 레이블이 상자가 아니라 점프 지점이라는 것입니다. 실행이 레이블에 착지하면 break나 닫는 중괄호를 만날 때까지, 다른 case 레이블을 가로질러서라도 아래의 모든 문장을 계속 실행합니다.

첫 번째 switch는 하나, , 을 모두 출력합니다. case 1에 일치한 뒤 그 아래 전부를 실행했기 때문입니다. 두 번째는 하나만 출력합니다. 이 동작을 폴스루라고 하고, break를 잊는 것이 고전적인 C switch 버그입니다. 컴파일에 실패하는 대신 프로그램이 조용히 틀립니다.

gcc -Wall -Wextra -Wimplicit-fallthrough로 컴파일하면 다음 case로 흘러드는 모든 case를 컴파일러가 짚어 줍니다.

마지막 case의 break는 엄밀히 말하면 없어도 됩니다. 어차피 블록이 거기서 끝나니까요. 그래도 쓰세요. 나중에 그 아래 새 case를 추가할 때 조용히 폴스루가 생기지 않도록 말입니다.

의도한 폴스루

의도적일 때 폴스루는 기능입니다. 사이에 문장 없이 레이블을 쌓는 것은 "이 값들은 같은 일을 한다"를 말하는 평범한 방법입니다.

레이블 셋이 본문 하나를 공유하며, 중복 코드도 긴 || 조건도 없습니다. 흘러들 문장이 없으므로 컴파일러는 이 모양에 대해 경고하지 않습니다.

사이에 문장이 있는 폴스루 - case 1이 실행되고 그다음 의도적으로 case 2로 이어지는 것 - 은 더 드물고 명시적인 주석을 달아 둘 만합니다. 읽는 사람에게 빠진 break가 결정이었다고 알려 줘야 하기 때문입니다.

switch (level) {
    case 3:
        printf("verbose\n");
        /* fall through */
    case 2:
        printf("info\n");
        /* fall through */
    case 1:
        printf("errors\n");
        break;
}

/* fall through */는 GCC의 경고가 알아보는 주석이므로, 진단 메시지도 함께 잠재웁니다.

문자로 분기하기

char가 정수 타입이므로 문자 분류에 자연스럽게 맞습니다.

case 'a':가 작은따옴표를 쓴다는 점을 보세요. 문자 상수이고, 그것은 그 문자의 정수 값일 뿐입니다. case "a":는 문자열이라 컴파일되지 않습니다.

enum으로 분기하기

C에서 가장 좋은 조합은 switch와 enum입니다. case 레이블이 읽을 수 있는 이름이 되고, switch가 모든 열거자를 처리하지 않을 때 컴파일러가 경고할 수 있습니다.

여기서 따라 할 만한 것이 둘 있습니다. 각 case가 return하므로 break가 필요 없습니다. return은 함수 자체를 떠나고, 그러면 switch도 끝납니다. 그리고 default가 없습니다. -Wswitch(-Wall에 포함됩니다)를 켜면 default를 빼 두었을 때, 누군가 다섯 번째 상태를 추가하고 이 함수를 잊는 날 컴파일러가 경고해 줍니다. default가 있었다면 그것을 감췄을 것입니다.

switch 안에서 변수 선언하기

switch 본문은 하나의 블록이므로, 한 case에서 한 선언은 그 뒤의 case들에서도 보입니다. 초기화되어 있으리라는 보장은 없지만요. 초기화를 건너뛰어 점프하는 것은 C에서 오류입니다.

switch (n) {
    case 1:
        int x = 10;        // C에서 오류: 레이블이 이런 식으로 선언 앞에 올 수 없다
        printf("%d\n", x);
        break;
    case 2:
        printf("%d\n", x); // 여기서 x는 존재하지만, 초기화된 적이 없다
        break;
}

지역 변수가 필요한 case는 자기 중괄호로 감싸세요.

switch (n) {
    case 1: {
        int x = 10;
        printf("%d\n", x);
        break;
    }
    case 2:
        printf("two\n");
        break;
}

switch인가 if-else인가?

다음이 모두 참일 때 switch를 택하세요. 식이 하나이고, 정수 타입이며, 고정된 상수들과 비교하는 경우입니다. 메뉴 처리, enum 상태 기계, 문자 분류, 명령 디스패치가 대표적입니다. 얻는 것은 가독성, 중복 값 검사, 그리고 처리되지 않은 열거자를 경고해 주는 컴파일러입니다.

검사에 범위(score >= 90), 부동소수점 값, 문자열(strcmp가 필요합니다), 여러 변수, 또는 &&||로 결합된 조건이 들어가면 if-else를 택하세요. 그중 어느 것도 case 레이블로 표현할 수 없습니다.

성능은 결정 요인인 경우가 드뭅니다. 컴파일러는 빽빽한 switch를 점프 테이블로, 성긴 것을 비교문으로 바꾸므로, case가 몇 개 안 될 때 두 형태는 구별되지 않습니다. 의도를 잘 드러내는 쪽을 고르세요.

자주 묻는 질문

C에서 switch 문은 어떻게 동작하나요?

switch (식)은 정수 식을 한 번 평가하고, 상수가 일치하는 case 레이블로 점프한 다음, break를 만나거나 switch가 끝날 때까지 거기서부터 실행합니다. 아무것도 일치하지 않으면 default가 있을 때 그리로 점프하고, 없으면 블록 전체를 건너뜁니다.

C의 switch에서 break가 왜 필요한가요?

case 레이블은 별개의 블록이 아니라 점프 지점이기 때문입니다. break가 없으면 실행이 다음 case의 문장들로 그대로 이어집니다. 이를 폴스루라고 합니다. break를 빠뜨리는 것은 C switch에서 가장 흔한 버그이고, gcc -Wimplicit-fallthrough가 잡아 줍니다.

C에서 문자열로 switch 할 수 있나요?

없습니다. C의 switch는 정수 식을 요구하므로 int, char, enum 값은 되지만 문자열, 실수, 범위는 안 됩니다. 문자열로 분기하려면 if-else 사슬에서 strcmp를 쓰거나, 문자열을 먼저 enum으로 매핑한 뒤 그것으로 switch 하세요.

C에서 언제 if-else 대신 switch를 써야 하나요?

정수나 문자 하나를 고정된 상수 목록과 비교할 때 switch를 쓰세요. 메뉴 명령, enum 상태, 문자 분류가 그렇습니다. 검사에 범위나 여러 변수가 얽히거나, 컴파일 타임 상수와의 동등 비교가 아닌 무언가가 들어가면 if-else 사슬을 쓰세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기