[c] switch 문이 왜 휴식을 취하도록 설계 되었습니까?

간단한 switch 문이 주어지면

switch (int)
{
    case 1 :
    {
        printf("1\n");
        break;
    }

    case 2 :
    {
        printf("2\n");
    }

    case 3 :
    {
        printf("3\n");
    }
}

사례 2에 break 문이 없으면 사례 3에 대한 코드 내에서 실행이 계속됨을 의미합니다. 이것은 우연이 아닙니다. 그런 식으로 설계되었습니다. 이 결정이 내려진 이유는 무엇입니까? 이것이 블록에 대한 자동 중단 의미를 갖는 것과 비교하여 어떤 이점이 있습니까? 근거는 무엇입니까?



답변

많은 답변 이 진술 을 요구하는 이유 로서 넘어 질 수있는 능력에 초점을 맞추는 것 같습니다 break.

나는 C가 설계되었을 때 이러한 구조가 어떻게 사용되는지에 대한 경험이 거의 없기 때문에 단순히 실수라고 생각합니다.

Peter Van der Linden은 자신의 저서 “Expert C Programming”에서 다음과 같이 설명합니다.

Sun C 컴파일러 소스를 분석하여 기본 폴 스루 사용 빈도를 확인했습니다. Sun ANSI C 컴파일러 프론트 엔드에는 244 개의 switch 문이 있으며 각 문에는 평균 7 개의 사례가 있습니다. 이 모든 경우의 3 %만으로 넘어집니다.

다시 말해서, 정상적인 스위치 동작은 97 %의 시간에 잘못 되었습니다. 이는 컴파일러에만있는 것이 아닙니다. 반대로이 분석에서 사용 된 추락은 종종 다른 소프트웨어보다 컴파일러에서 더 자주 발생하는 상황 (예 : 하나 또는 두 개의 피연산자를 가질 수있는 연산자를 컴파일 할 때)이었습니다. :

switch (operator->num_of_operands) {
    case 2: process_operand( operator->operand_2);
              /* FALLTHRU */

    case 1: process_operand( operator->operand_1);
    break;
}

케이스 폴 스루는 결함으로 널리 인식되어 있으며 위에서 보인 것처럼 보풀을 알려주는 특별한 주석 규칙도 있습니다. “이는 실제로 폴 스루가 필요한 경우의 3 % 중 하나입니다.”

C #이 각 사례 블록의 끝에 명시 적 점프 명령문을 요구하는 것이 좋습니다 (단일 문장 블록이있는 한 여러 사례 레이블을 쌓을 수는 있음). C #에서는 한 사례가 다른 사례로 넘어갈 수 있습니다 goto.를 사용하여 다음 사례로 넘어 가서 명시 적으로 넘어야합니다 .

Java가 C 의미를 벗어날 기회를 얻지 못한 것은 너무 나쁩니다.


답변

여러 가지면에서 c는 표준 어셈블리 관용구에 대한 깔끔한 인터페이스입니다. 점프 테이블 구동 흐름 제어를 작성할 때, 프로그래머는 “제어 구조”를 통해 넘어 지거나 뛰어 내릴 수 있습니다.

그래서 c도 같은 일을합니다.


답변

더프의 장치를 구현하려면 분명히 :

dsend(to, from, count)
char *to, *from;
int count;
{
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}


답변

사례가 암시 적으로 중단되도록 설계된 경우에는 실패 할 수 없었습니다.

case 0:
case 1:
case 2:
    // all do the same thing.
    break;
case 3:
case 4:
    // do something different.
    break;
default:
    // something else entirely.

모든 경우에 스위치가 암시 적으로 발생하도록 설계된 경우 스위치를 선택할 수 없습니다. 스위치 케이스 구조는보다 유연하게 설계되었습니다.


답변

switch 문에있는 case 문은 단순히 레이블입니다.

값을 켤 때 switch 문은 본질적으로 goto를 수행합니다. 일치하는 값으로 레이블을.

즉, 다음 레이블 아래의 코드를 통과하지 않으려면 나누기가 필요합니다.

이것이 이런 식으로 구현 된 이유에 대해서는 switch 문의 폴-스루 특성이 일부 시나리오에서 유용 할 수 있습니다. 예를 들면 다음과 같습니다.

case optionA:
    // optionA needs to do its own thing, and also B's thing.
    // Fall-through to optionB afterwards.
    // Its behaviour is a superset of B's.
case optionB:
    // optionB needs to do its own thing
    // Its behaviour is a subset of A's.
    break;
case optionC:
    // optionC is quite independent so it does its own thing.
    break;


답변

다음과 같은 것을 허용하려면 :

switch(foo) {
case 1:
    /* stuff for case 1 only */
    if (0) {
case 2:
    /* stuff for case 2 only */
    }
    /* stuff for cases 1 and 2 */
case 3:
    /* stuff for cases 1, 2, and 3 */
}

case키워드를 goto레이블 로 생각하면 더 자연스럽게 나타납니다.


답변

여러 사례에서 동일한 코드 (또는 동일한 코드를 순서대로)를 실행해야하는 경우 코드 중복을 제거합니다.

어셈블리 언어 수준에서는 각 언어 사이의 구분 여부에 관계가 없으므로 어쨌든 추락에 대한 오버 헤드가 전혀 없습니다. 따라서 특정 경우에 큰 이점을 제공하므로 허용하지 않는 이유는 무엇입니까?