작동해야하는 스위치에서 케이스를 건너 뛰기 위해 if (0)을 사용하고 있습니까?


122

C ++ switch 문에서 두 가지 경우가 모두 세 번째 경우로 넘어 가고 싶은 상황이 있습니다. 특히 두 번째 경우는 세 번째 경우로 넘어 가고 첫 번째 경우도 두 번째 경우 통과 하지 않고 세 번째 경우로 넘어갑니다 .

나는 멍청한 생각을 가지고 시도해 보았고 효과가있었습니다! 나는 두 번째의 경우 포장 if (0) {... }. 다음과 같이 보입니다.

#ifdef __cplusplus
#  include <cstdio>
#else
#  include <stdio.h>
#endif

int main(void) {
    for (int i = 0; i < 3; i++) {
        printf("%d: ", i);
        switch (i) {
        case 0:
            putchar('a');
            // @fallthrough@
            if (0) {        // fall past all of case 1 (!)
        case 1:
            putchar('b');
            // @fallthrough@
            }
        case 2:
            putchar('c');
            break;
        }
        putchar('\n');
    }
    return 0;
}

실행하면 원하는 출력을 얻습니다.

0: ac
1: bc
2: c

나는 C와 C ++ (둘 다 clang과 함께)에서 시도해 보았고 같은 일을했습니다.

내 질문은 : 이것이 유효한 C / C ++입니까? 그것이하는 일을해야합니까?


34
예, 이것은 유효하며 Duff의 장치 와 거의 동일한 이유로 작동합니다.
dxiv

42
이와 같은 코드는 가독성과 유지 보수성에 조금이라도 신경을 쓰는 환경에서 코드 연습에서 벗어나게 할 것입니다.
Andrew Henle

16
이것은 끔찍합니다. Duff의 장치보다 훨씬 더 끔찍합니다. 관련, 나는 또한 최근에 switch(x) { case A: case B: do_this(); if(x == B) also_do_that(); ... }. 그것은 또한 IMO, 끔찍했습니다. 두 곳에서 한 줄을 반복해야하더라도 마치 문처럼 작성하십시오. 함수와 변수 (및 문서!)를 사용하여 실수로 나중에 한 곳에서만 업데이트 할 위험을 줄이십시오.
일까 추

50
:-) 그 코드를보고 다치거나 불구가 된 사람들에게는 좋은 생각 이라고 말하지 않았습니다 . 사실 멍청한 생각이라고 말했어.
Mark Adler

4
이 같은 스위치 내부 구조가 :( RAII와 함께 잘 작동하지 않는 주
오리 음매

답변:


58

예, 이것은 허용되며 원하는 것을 수행합니다. A에 대한 switch문은 C ++ 표준은 말합니다 :

대 / 소문자 및 기본 레이블 자체는 제어 흐름을 변경하지 않으며 이러한 레이블에서 방해받지 않고 계속됩니다. 스위치에서 나가려면 break를 참조하십시오.

[참고 1 : 일반적으로 스위치의 주제 인 하위 문은 복합이고 case 및 기본 레이블은 (복합) 하위 문에 포함 된 최상위 문에 표시되지만 필수는 아닙니다. 선언문은 switch 문의 하위 문에 나타날 수 있습니다. — 끝 참고]

따라서 if명령문이 평가 될 때 if중간 케이스 레이블에 관계없이 명령문 의 규칙에 따라 제어 흐름이 진행됩니다 .


13
이에 대한 구체적인 사례로 Boost.Coroutines 에서 C ++ 03 규칙을 사용하여 코 루틴을 구현하기 위해이 규칙 (및 C ++의 다른 6 가지 코너 사례)을 활용하는 위장 변동 매크로 세트를 살펴볼 수 있습니다 . 그것들은 C ++ 20 전까지는 언어의 일부가 아니었지만,이 매크로는 그것들을 작동하게 만들었습니다.
Cort Ammon

60

네, 작동합니다. C의 switch 문에 대한 case 레이블은 goto 레이블과 거의 똑같습니다 (중첩 된 switch 문에서 작동하는 방법에 대한 몇 가지주의 사항이 있음). 특히, 그들은 "사례 내부"라고 생각하는 문장에 대한 블록을 스스로 정의하지 않으며, goto에서 할 수있는 것처럼 블록의 중간으로 점프하는 데 사용할 수 있습니다. 블록 중간으로 점프 할 때 변수 초기화 등의 점프와 관련하여 goto와 동일한주의 사항이 적용됩니다.

그렇게 말하면 실제로 다음과 같이 goto 문으로 작성하는 것이 더 분명합니다.

    switch (i) {
    case 0:
        putchar('a');
        goto case2;
    case 1:
        putchar('b');
        // @fallthrough@
    case2:
    case 2:
        putchar('c');
        break;
    }

1
"블록 중간으로 점프 할 때 변수 초기화 등을 뛰어 넘는 것과 관련하여 goto와 동일한 경고가 적용됩니다." 이러한 경고는 무엇입니까? 당신은 할 수없는 변수의 초기화를 통해 이동합니다.
날개를 가진 소행성

4
@AsteroidsWithWings, 표준을 준수하는 관점에서 "할 수 없다"는 뜻입니까, 아니면 컴파일러가 허용하지 않는 일종의 실용적인 관점에서 볼 수 있습니까? 내 GCC는 경고와 함께 C 모드에서 허용하기 때문입니다. 하지만 C ++ 모드에서는 허용되지 않습니다.
일까 추

5
@quetzalcoatl gcc-9 및 clang-6은 둘 다이 코드를 허용하여 잠재적으로 초기화되지 bee않았 음을 경고 합니다.
Ruslan

7
goto더 깨끗한 솔루션을 사용할 때 잘못하고 있다는 것을 알고 있습니다 .
Konrad Rudolph

9
@KonradRudolph : goto많은 악의를 가지고 있지만 수동으로 복잡한 제어 구조를 만들지 않는 경우에는 정말 불쾌한 것이 없습니다. "유해한 것으로 간주되는 고토"는 컴파일러가 내 보낸 asm처럼 보이는 HLL (예 : C) 코드를 작성하는 것이 었습니다. 순방향 전용 (개념 상 break또는 초기 와 다르지 않음 return), 가능성이 낮은 재시도 루프 전용 (공통 흐름 경로를 모호하게하는 것을 방지하고 nested- 부족을 보상) 등과 같은 goto의 구조화 된 사용이 많이 있습니다 continue.
R .. GitHub STOP HELPING ICE

28

다른 답변에서 언급했듯이 이것은 표준에서 기술적으로 허용되지만 향후 코드 독자에게는 매우 혼란스럽고 명확하지 않습니다.

이것이 switch ... case문이 많은 인라인 코드가 아닌 함수 호출로 작성되어야하는 이유 입니다.

switch(i) {
case 0:
    do_zero_case(); do_general_stuff(); break;
case 1:
    do_one_case(); do_general_stuff(); break;
case 2:
    do_general_stuff(); break;
default:
    do_default_not_zero_not_one_not_general_stuff(); break;
}

질문의 코드는 do_general_stuff기본값이 아니라 케이스 2 (및 0 및 1) 에만 해당됩니다 . 그러나 i0..2 범위 밖에서 는 스위치를 실행하지 않습니다 .
Peter Cordes

@PeterCordes-답변의 코드는 do_general_stuff기본값이 아니라 케이스 2 (및 0 및 1)에만 해당됩니다.
Pete Becker

제안-기본 케이스를 제거하거나 이름을 변경해야합니까? 다른 함수 이름을 놓치기 쉽습니다.
I.Am.A.Guy 2010 년

@PeteBecker : 오, 나는 그것을 놓친 방법 IDK generaldefault다른 단어였다. OTOH, 중간 글자가 뒤섞여도 인간이 보통 단어를 읽을 수 있다는 것은 알려진 사실입니다. 우리는 시작과 끝을 보는 경향이 있으므로 중간 만 다른 것은 스키밍 가능성에 이상적이지 않습니다. 아마도 do_접두사를 제거하십시오 .
Peter Cordes

1
@supercat : "잘 알려진 사실"은 중간 글자를 다른 글자로 바꾸는 것이 아니라 순서를 섞는 것에 관한 것입니다. "시알 름이 그레 닐에서 사실이라면, 당신은 티즈를 강타 할 것입니다."
Michael Karcher
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.