switch는 범위 비교가 아니라 값 기반 분기에서 힘을 발휘합니다.
if/else대신switch를 써도 되는지 판단하고 싶다break를 하나 빼먹어서 왜 다음 case까지 실행됐는지 확인하고 싶다- 의도적인 fallthrough를 어떻게 표시해야 하는지 다시 보고 싶다
숏컷 코드
switch (command) {
case CMD_START:
start_engine();
break;
case CMD_STOP:
stop_engine();
break;
default:
fprintf(stderr, "unknown command\n");
break;
}반대로 score >= 90 같은 범위 분기는 여전히 if/else가 더 낫습니다.
분기 흐름
switch (expr)는 하나의 정수/문자/enum 값에 대해 여러 case를 나누는 분기문입니다. 값 하나를 기준으로 갈라지는 흐름일 때 적합하고, 범위 비교가 많아지면 if/else 쪽이 더 자연스럽습니다.
switch (score) {
case 0:
puts("zero");
break;
default:
puts("other");
break;
}흐름 제어
switch (menu) {
case 1:
printf("save\n");
case 2:
printf("quit\n");
break;
}위 코드는 menu == 1이어도 quit까지 실행됩니다. C의 switch는 case 내부에서 자동으로 멈추지 않습니다.
그래서 기본 태도는 이겁니다.
- 대부분 case 끝에는
break - 의도적으로 흘려보낼 때만 명시
switch (grade) {
case 'A':
case 'B':
printf("pass\n");
break;
case 'C':
printf("retry\n");
break;
}이 패턴은 괜찮습니다. 여러 case가 같은 동작을 공유하니까 읽는 사람도 자연스럽게 이해할 수 있습니다.
조금 더 위험한 형태는 "중간 로직 실행 후 다음 case로 일부러 흘리는" 경우입니다.
switch (level) {
case 3:
enable_logging();
/* fallthrough */
case 2:
enable_debug();
break;
}이 경우에는 주석이나 속성으로 의도를 분명히 남기는 편이 맞습니다.
반대로 범위 분기에는 여전히 switch보다 if/else가 낫습니다.
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
}switch (score)로 90~100을 일일이 나누는 방식보다 읽기 쉽고, 의도도 더 분명합니다.
case 구성
예상 가능한 case를 다 썼다고 느껴도, 외부 입력이나 잘못된 상태가 들어오면 빠지는 값이 생길 수 있습니다.
- enum이더라도 외부 정수 입력은 범위 밖 값일 수 있다
- default가 없으면 조용히 아무 일도 안 하고 지나갈 수 있다
- 같은 동작을 공유하는 case 묶음은 자연스럽지만, 중간 로직 뒤 fallthrough는 의도 표시가 없으면 거의 실수처럼 읽힙니다.
case 안에서 지역 변수를 선언하고 초기화를 넘나드는 코드는 쉽게 꼬입니다. case별 상태가 필요하면 중괄호 블록으로 scope를 나누는 편이 안전합니다.
체크포인트
- 값 기반 분기면
switch - 범위 분기면
if/else - 기본은
break - fallthrough는 의도 표시
- 예외값 대비
default
주의할 점
switch 안에서 변수를 선언하고 case를 넘나들면 초기화 건너뜀 문제로 바로 복잡해집니다. case별로 지역 상태가 필요하면 중괄호 블록으로 감싸서 scope를 분리하는 편이 안전합니다.
참고 링크
1 sources