이번에는 if
문의 친구인 switch
문에 대해서 알아보자.
이 친구가 if의 친구인 이유는 그만큼 if문과 정말 비슷하기 때문이다. 아래의 간단한 강아지 시뮬레이션을 보자.
#include <stdio.h>
int main() {
int input;
printf("마이펫 \n");
printf("무엇을 하실 것인지 입력하세요 \n");
printf("1. 밥주기 \n");
printf("2. 씻기기 \n");
printf("3. 재우기 \n");
scanf("%d", &input);
if (input == 1) {
printf("아이 맛있어 \n");
} else if (input == 2) {
printf("아이 시원해 \n");
} else if (input == 3) {
printf("zzz \n");
} else {
printf("무슨 명령인지 못 알아 듣겠어. 왈왈 \n");
}
return 0;
}
마이펫
무엇을 하실 것인지 입력하세요
1. 밥주기
2. 씻기기
3. 재우기
1
아이 맛있어
위와 같이 3가지의 명령어에 따라서 반응하고 알 수 없는 명령어의 경우 "무슨 명령인지 못 알아 듣겠어. 왈왈"
를 출력한다고 해보자. 그런데 만약 여기서 명령어를 10개로 늘린다면 어떨까? 아니면 100개가 늘어난다면??
if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
} else if (...) {
...
}
이런식으로 계속 코드를 작성해야할 것이다. 이러면 보는 사람도 불편하고 작성하는 사람도 힘들다.
이럴 때 사용하는 것이 마로 switch
이다. 위와 같이 동일한 변수에 대한 비교문이 반복될때 사용한다.
#include <st될dio.h>
int main() {
int input;
printf("마이펫 업그레이드\n");
printf("무엇을 하실 것인지 입력하세요 \n");
printf("1. 밥주기 \n");
printf("2. 씻기기 \n");
printf("3. 재우기 \n");
scanf("%d", &input);
switch (input) {
case 1:
printf("아이 맛있어 \n");
break;
case 2:
printf("아이 시원해 \n");
break;
case 3:
printf("zzz \n");
break;
default:
printf("무슨 명령인지 못 알아 듣겠어. 왈왈 \n");
break;
}
return 0;
}
여기서 주의해야할 점.
switch
문에 사용될 변수로는 반드시 정수 데이터를 보관하면 변수여야 한다. 다시말해서 '변수' 부분에 들어가는 변수들의 타입은 char
, short
, int
, long
중에 하나여야 한다. 만약 위 코드의 input
자리에 float
나 double
가 들어가면 오류가 발생한다.
변수 == 1
일 때 가장 맨 위의 case가 실행이 되는데 print문이 실행되고 나서 break;
가 실행이 되어야 swith
문을 빠져나간다. 만약 변수 == 2
라면 앞서 다른 case는 넘어가고 case 2
가 실행이 된다. 만약 break
를 작성하지 않는다면 아래와 같이 실행된다.
마이펫 업그레이드
무엇을 하실 것인지 입력하세요
1. 밥주기
2. 씻기기
3. 재우기
1
아이 맛있어
아이 시원해
zzz
무슨 명령인지 못 알아 듣겠어. 왈왈
case 1이 실행이 되었지만 break로 swtich문을 빠져나오지 못하여 아래 case까지 줄줄이 실행되는 것이다.
여기서 또 주의해야할 점
'값' 의 위치하는 것들은 모두 상수 이여야한다. 만약 값 부분에 변수가 들어오면 오류가 발생한다.(이유는 아래 쪽에 설명 되어 있다.)
그리고 마지막에 default
는 if 문에서 else
와 같은 역할을 한다. 이도저도 아닌 값이면 실행되는 구문이다.
#include <stdio.h>
int main() {
char input;
printf("(소문자) 알파벳 읽기\n");
printf("알파벳 : ");
scanf("%c", &input);
switch (input) {
case 'a':
printf("에이 \n");
break;
case 'b':
printf("비 \n");
break;
case 'c':
printf("씨 \n");
break;
default:
printf("죄송해요.. 머리가 나빠서 못 읽어요 \n");
break;
}
return 0;
}
(소문자) 알파벳 읽기
알파벳 : b
비
사실 아까 위에서 switch
문은 정수데이터만 처리한다고 했었는데 위의 예시를 보면 문자데이터도 들어간다.
왜 문자 데이터가 들어가도 처리가 될까?
만약 의문이 쉽게 해결하셨다면 복습을 잘한 사람일 것이다. 왜냐하면 컴퓨터는 저번에 배웠듯이 문자와 숫자를 구분하지 못한다.( 문자 입력 받기 )
컴퓨터는 모든 문자를 숫자로 처리한 다음에 우리에게 보여줄 때만 문자로 보여준다. 따라서 문자 = 숫자 라고 해도 무방하다.
이쯤 되면 의문이 하나가 생긴다.
정말로 switch
가 필요한 것인가? if-else
로도 다 해결할 수 있는데 굳이 겉으로 보기에 깔끔하게 보인다고 switch
를 사용해야하는 것인가? 내부적으로 switch
와 if-else
가 차이가 없는 것인가?
매우 훌륭한 질문이다. 자세히 이해하기 위해선 어셈블리어의 대한 이해가 필요하다(https://blog.naver.com/kki2406/80041410085) 에서 자세히 볼 수 있다.
위 링크를 통해 이해한다면 더할나위 없지만 간단하게 설명을 해보자면
위의 사진은 같은 소스 코드를 if
와 switch
에 대해서 나타낸 것이다. 사실 외형적으로 처리하는데에는 별 차이가 없다. 단지 내부적으로 어떻게 처리되냐가 다를 뿐이다.
먼저 if 문은 각 경우의 값들을 다 비교한다. 여기선 3번 비교한다. if 일때 1번, else if 일떄 2번, else 일때 비교 없이 자동으로 처리되므로 3번.
if 문은 case
에 대해서 값을 비교하므로 최악의 경우 모든 case
에 대해서 값을 비교하는 연산(어셈블리어에서 CMP
연산)을 하게 된다.
그런데 switch
문에서는 사뭇 다르다. switch
의 경우 내부적으로 jump table
이라는 것을 생성하는데 이때 case
의 값에 따라서 jump table
의 크기가 달라진다. 예를들의 case :1
~ case: 10
까지 있다면 jump table
에는 0부터 9까지 들어가게 된다. 여기서 우리가 앞서 case : 값
에서 값부분에 변수를 넣으면 왜 안되는지 이유를 알 수 있다. jump table
은 프로그램 초기에 작성되기 때문에 '값' 부분에 변수가 오면 jump table
에서 무엇이 올지 알 수 없으므로 변수를 사용하면 안된다.
이 값들은 무엇을 의미하면 각 case
별로 명령들이 위치한 곳의 주소를 가리키게 된다. 만약 1 인 지점으로 점프하게 되면 "아이 시원해"가 나오고 0 인 지점으로 점프하면 "아이 맛있어"가 나오게 된다. 이제, 변수값에 따라 변수가 3이면 jump table
의 3 번째 원소를 찾아서 그 값에 해당되는 곳으로 점프하게 된다.
(실제로 switch
문의 처리과정은 이보다 더 복잡하나 쉽게 설명한 것이다)
따라서 switch
를 사용하면 case
에 따라서 CMP
연산이 늘어나는 것이 아니라 jump table
의 크키만 커질 뿐 성능에는 전혀 영향을 받지 않게 된다.
결론적으로 말하자면 switch
를 효과적으로 처리되기 위해선 case
의 '값'이 그리 크지 않고, '값'들이 순차적으로 정렬되어 있고, 그 '값' 들의 차이가 크지 않다면 최고의 효율적인 switch
를 사용할 수 있다.