본문 바로가기

지식의 방

[펌]너희가 switch 를 아느냐?

출처 : 온라인 게임 개발자 이창연(lisyoen) http://blog.empas.com/lisyoen/

switch 는 C/C++, Java, C#, J++, J# 등에서 널리 쓰이는 조건 분기문이다.
다른 언어에서도 비슷한 기능의 조건 분기문이 존재한다.

C/C++ 에서는 그 제약이 크다. switch 구문에서는 반드시 정수(int)만 비교할 수 있고 분기하는 case 에는 상수(constant value)만 넣을 수 있다. (다른 고급언어들은 부동소수점, 문자열 심지어는 사용자 정의 데이터 타입 까지 비교할 수 있다) 이 제약은 고속 스위칭(switching)을 위해 존재하는 것이다.

과연 C/C++ 의 switch 구문은 어떤 방식으로 작동할까?

흔히 알려진 바로는 switch 구문이 if/else 비교 없이 해당 case 로 곧장 jump 하기 때문에 속도가 빠르다고 한다. 이것은 부분적으로 사실이다. 컴파일러가 이런 방식을 사용하게 된 것은 DOS 시절의 WATCOM C 부터였다고 한다.

프로그래머라면 생각해보자. 비교할 값만으로 jump 하려면 Address table 이 필요하다. 과연 Address table 만으로 switch 구문을 비교 없이 jump 하도록 구성할 수 있을까? 오래 생각하지 말자. 당연히 불가능하다.

32bit 플랫폼에서 int 는 4Giga 의 범위를 갖는다. Address point 도 4bytes 일 경우 Address table 은 최대 16GB 의 메모리를 사용할 수도 있다. (case 0, case 0xFFFFFFFF)

이에 대한 해답은. 바로 '조합' 이다.

즉, 연속적이거나 집적된 case 의 경우에는 해당 범위만큼의 테이블을 만들어 jump 하고 듬성듬성 떨어져 있는 case 의 경우는 if/else 를 이용하여 case 수 만큼 비교후 분기하는 것이다.
VC++ 6.0 과 7.0 의 디스어셈블리 기능을 이용해 분석해본바에 의하면 switch 구문은 다음과 같은 규칙을 갖고 기계어를 생성한다.

1. case 가 3개 이하인 경우에는 if/else 로 일일히 비교후 분기 한다.
2. case 가 4개 이상이고, 최소 case 와 최대 case 의 차이가 254 이하인 경우에는 Address table 을 만들어 jump 한다. (이 과정에서 최대 약 1KB 의 Address table 이 생성된다. switch 를 잘못 쓰면 1KB 의 디스크 공간과 메모리를 낭비할 수도 있다)
3. 최소 case 와 최대 case 의 차이가 255 이상인 경우에는 if/else 로 비교후 분기한다. 단, 최소 case 를 포함하며 규칙2의 조건을 만족하는 부분집합이 존재할 경우 해당 case 들은 Address table 을 만들어 jump 한다.

예>
case 0, 1, 2 -> if/else 로 분기 (규칙 1)
case 0, 1, 2, 3, 4 -> Address table 로 분기 (규칙2)
case 0, 1, 2, 3, 4, 100 -> Address table 로 분기 (규칙 2)
case 0, 1, 2, 3, 4, 100, 300 -> 0~100 까지는 Address table 로 분기. 300 은 if/else 로 분기(규칙3)
case 0, 300, 301, 302, 303, 304 -> 모두 if/else 로 분기 (규칙3)

이 외에도 몇 가지 규칙이 더 있을것으로 보인다. 하지만 이것 만으로도 벌써 switch 구문을 효과적으로 활용하기 위한 제한사항들이 머리속에 마구 떠오를 것이다. (5번째 예와 같이 구성해서는 안될것이다)

이런 작은 차이로부터 우리는 명품을 끌어낸다
반응형