조건문 switch
지난 장에서 if
, else if
, else
문을 통해 조건에 따라 프로그램의 흐름을 제어하는 방법을 학습했습니다.
이 문법은 매우 유연하고 강력하지만, 하나의 변수 값이 여러 가지 경우의 수에 따라 각각 다른 동작을 해야 할 때는 else if
를 길게 나열해야 하는 경우가 발생합니다.
예를 들어 사용자 입력에 따라 요일을 판별하거나, 메뉴 선택에 따라 다른 기능을 실행해야 할 때 말이죠.
이런 상황에서 if-else if
체인보다 더 깔끔하고 효율적인 대안을 제공하는 것이 바로 switch
문입니다.
switch
문은 하나의 변수(또는 표현식)의 값에 따라 여러 case
중 하나를 선택하여 실행하는 조건문입니다.
switch
문이란 무엇인가?
switch
문은 주어진 표현식의 값을 평가하여 그 값과 일치하는 case
레이블로 프로그램의 실행 흐름을 점프시킵니다.
여러 개의 가능한 값 중 하나를 선택하여 처리할 때 특히 유용합니다.
switch
문을 사용하는 경우
- 하나의 정수형 변수(또는 정수형으로 평가될 수 있는 표현식)의 값이 여러 개의 특정 값 중 하나일 때.
- 다수의
else if
문이 동일한 변수에 대한 동등 비교(==
)를 반복하는 경우.
switch
문 제약사항
switch
문의 조건 표현식은 반드시 정수 계열 타입이어야 합니다. (예:int
,char
,enum
,long
,bool
등). 실수형(float
,double
)이나 문자열(std::string
)은switch
문의 조건으로 직접 사용할 수 없습니다.- 각
case
레이블 뒤에 오는 값은 반드시 상수(Constant) 여야 합니다. 변수는 사용할 수 없습니다.
switch
문 형식 및 기본 사용법
switch
문의 기본적인 형식은 다음과 같습니다.
switch (표현식) {
case 상수값1:
// 표현식의 값이 상수값1과 같을 때 실행할 코드
break; // break 문은 필수!
case 상수값2:
// 표현식의 값이 상수값2와 같을 때 실행할 코드
break;
case 상수값3:
// 표현식의 값이 상수값3과 같을 때 실행할 코드
break;
default: // 선택 사항
// 위의 어떤 case에도 해당하지 않을 때 실행할 코드
break; // default도 보통 break를 사용 (습관화)
}
switch (표현식)
: 괄호 안의표현식
은 정수 계열 타입으로 평가되어야 합니다.case 상수값
:case
키워드 뒤에표현식
과 비교할상수값
을 적고 콜론(:
)을 붙입니다.상수값
은 중복될 수 없습니다.break;
:case
블록의 끝에break
문은 매우 중요합니다.break
문은switch
문을 즉시 종료하고switch
문 다음의 코드로 실행 흐름을 넘깁니다.default:
: 선택 사항입니다.switch
문의표현식
이 어떤case
의상수값
과도 일치하지 않을 때default
블록의 코드가 실행됩니다.default
는 어떤 위치에 두어도 상관없지만, 일반적으로 가장 마지막에 둡니다.
#include <iostream>
int main() {
int choice;
std::cout << "메뉴를 선택하세요 (1:불고기, 2:비빔밥, 3:냉면, 4:음료): ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "불고기를 선택하셨습니다." << std::endl;
std::cout << "가격은 12000원입니다." << std::endl;
break; // switch 문 종료
case 2:
std::cout << "비빔밥을 선택하셨습니다." << std::endl;
std::cout << "가격은 9000원입니다." << std::endl;
break; // switch 문 종료
case 3:
std::cout << "냉면을 선택하셨습니다." << std::endl;
std::cout << "가격은 8000원입니다." << std::endl;
break; // switch 문 종료
case 4:
std::cout << "음료를 선택하셨습니다." << std::endl;
std::cout << "가격은 2000원입니다." << std::endl;
break; // switch 문 종료
default: // 어떤 case에도 해당하지 않을 경우
std::cout << "잘못된 메뉴 번호입니다." << std::endl;
break; // default도 break를 붙이는 것이 일반적
}
std::cout << "주문 처리를 완료했습니다." << std::endl;
return 0;
}
break
문의 중요성: Fall-through
switch
문에서 break
문을 생략하면, 해당 case
블록의 코드가 실행된 후 다음 case
블록으로 실행 흐름이 연속적으로 흘러들어갑니다(Fall-through).
이는 의도적인 경우도 있지만, 대부분은 프로그래머의 실수로 발생하여 논리적 오류를 유발합니다.
#include <iostream>
int main() {
char grade = 'B';
switch (grade) {
case 'A':
std::cout << "탁월합니다!" << std::endl;
// break; // 여기에 break가 없으면 다음 case로 넘어감
case 'B':
std::cout << "훌륭합니다!" << std::endl;
// break; // 여기에 break가 없으면 다음 case로 넘어감
case 'C':
std::cout << "잘 했습니다." << std::endl;
break; // 여기는 break가 있으므로 switch 문 종료
default:
std::cout << "다시 시도하세요." << std::endl;
break;
}
// 출력:
// 훌륭합니다!
// 잘 했습니다.
return 0;
}
위 예시에서 grade
가 'B'
이므로 "훌륭합니다!"가 출력된 후, break
가 없기 때문에 case 'C'
로 Fall-through되어 "잘 했습니다."까지 출력됩니다.
이는 보통 의도하는 바가 아닙니다.
의도적인 Fall-through:
가끔은 여러 case
가 동일한 코드를 공유해야 할 때 의도적으로 Fall-through를 사용할 수 있습니다.
#include <iostream>
int main() {
int month = 2; // 2월
switch (month) {
case 1: // 1월
case 3: // 3월
case 5: // 5월
case 7: // 7월
case 8: // 8월
case 10: // 10월
case 12: // 12월
std::cout << month << "월은 31일까지 있습니다." << std::endl;
break;
case 4: // 4월
case 6: // 6월
case 9: // 9월
case 11: // 11월
std::cout << month << "월은 30일까지 있습니다." << std::endl;
break;
case 2: // 2월
std::cout << month << "월은 28일 또는 29일까지 있습니다." << std::endl;
break;
default:
std::cout << "잘못된 월입니다." << std::endl;
break;
}
// 출력: 2월은 28일 또는 29일까지 있습니다.
return 0;
}
이처럼 연속된 case
레이블 뒤에 코드를 작성하지 않고 break
도 생략하여 여러 case
가 하나의 코드 블록으로 Fall-through되도록 할 수 있습니다.
이 경우 Fall-through가 의도적임을 명시하기 위해 C++17부터는 [[fallthrough]];
속성(attribute)을 사용할 수 있습니다.
// C++17 이상
case 'A':
std::cout << "매우 잘함!" << std::endl;
[[fallthrough]]; // 컴파일러에게 의도적인 fall-through임을 알림
case 'B':
std::cout << "잘함!" << std::endl;
break;
if-else if
vs. switch
두 조건문 모두 여러 조건을 처리할 수 있지만, 각각 장단점이 있습니다.
if-else if
체인의 장점
- 유연성: 다양한 타입의 조건(정수, 실수, 문자열, 복잡한 논리 표현식 등)을 사용할 수 있습니다.
- 범위 비교: 특정 범위(
score >= 80 && score < 90
)를 비교하는 데 유리합니다. - 논리 연산자 사용:
&&
,||
,!
와 같은 논리 연산자를 사용하여 복잡한 조건을 쉽게 조합할 수 있습니다.
switch
문의 장점
- 명확성: 하나의 변수 값을 기준으로 여러
case
를 명확하게 나열할 수 있어 코드의 구조가 한눈에 들어옵니다. - 효율성 (잠재적): 컴파일러가
switch
문을 최적화하여if-else if
체인보다 더 빠르게 실행될 수 있도록 할 가능성이 있습니다 (특히case
가 많을 경우 점프 테이블 등을 사용). - 가독성 (특정 상황): 동일한 변수에 대한 다수의 동등 비교를 처리할 때
if-else if
보다 가독성이 좋습니다.
언제 무엇을 사용할까?
- 범위 비교, 복잡한 논리, 실수/문자열 조건이라면
if-else if
를 사용하세요. - 하나의 정수형 변수 값이 여러 개의 특정 상수 중 하나와 일치하는 경우라면
switch
문이 더 적합하고 가독성이 좋습니다.