IT이야기

스위치 케이스의 구문은 유효하지만 가치가 없는 구문인가?

cyworld 2022. 5. 9. 22:03
반응형

스위치 케이스의 구문은 유효하지만 가치가 없는 구문인가?

약간의 오타를 통해 나는 우연히 이 구조를 발견했다.

int main(void) {
    char foo = 'c';

    switch(foo)
    {
        printf("Cant Touch This\n");   // This line is Unreachable

        case 'a': printf("A\n"); break;
        case 'b': printf("B\n"); break;
        case 'c': printf("C\n"); break;
        case 'd': printf("D\n"); break;
    }

    return 0;
}

...인 것 같다.printf맨 위에switch진술은 유효하지만, 또한 완전히 도달할 수 없다.

접근할 수 없는 코드에 대한 경고도 없이 깔끔하게 컴파일을 받았는데, 이건 무의미해 보여

컴파일러가 연결할 수 없는 코드로 플래그를 표시해야 하는가?
이게 무슨 소용이야?

아마도 가장 유용한 것은 아니지만, 완전히 쓸모없는 것은 아닐 것이다.다음에서 사용할 수 있는 로컬 변수를 선언하는 데 사용할 수 있음switch범위

switch (foo)
{
    int i;
case 0:
    i = 0;
    //....
case 1:
    i = 1;
    //....
}

표준 ()N1579 6.8.4.2/7)에는 다음과 같은 샘플이 있다.

예: 인공 프로그램 조각 내

switch (expr)
{
    int i = 4;
    f(i);
case 0:
    i = 17;
    /* falls through into default code */
default:
    printf("%d\n", i);
}

식별자가 있는 개체i(블록 내에) 자동 저장 지속 시간이 있지만 초기화되지 않으며, 따라서 제어 식이 0이 아닌 값을 갖는 경우 에 대한 호출printf함수는 불확실한 값에 접근할 것이다.마찬가지로, 함수에 대한 호출f손이 닿지 않다

P.S. BTW, 샘플은 유효한 C++ 코드가 아니다.그런 경우에는 ()N4140 6.7/3, 강조 표시 내 항목:

지 않는 한 변수가 사소한 기본 생성자와 사소한 소멸자, 이런 종류 중 하나 또는 선행 형식이고 배열을cv-qualified 버전과 스칼라 타입, 클래스 형식을 가진 자동 저장 기간 따라 변화무쌍하는 범위에 있는 수준까지 범위에 없는 지점에서 jumps90 프로그램ill-formed 있다.d이니셜라이저 없이 닫힘(8.5).


90) a의 조건으로부터의 이전switch사례 라벨에 대한 진술은 이 점에서 점프로 간주된다.

그래서 교체int i = 4;와 함께int i;유효한 C++가 된다.

이게 무슨 소용이야?

그래. 만약 당신이 첫 번째 라벨 앞에 선언문을 붙인다면, 이것은 완벽하게 타당할 수 있다.

switch (a) {
  int i;
case 0:
  i = f(); g(); h(i);
  break;
case 1:
  i = g(); f(); h(i);
  break;
}

선언과 문장의 규칙은 일반적으로 블록에 대해 공유되기 때문에, 그것은 또한 거기서도 문장이 가능하도록 허용하는 것과 같은 규칙이다.


또한 첫 번째 문장이 루프 구조인 경우 사례 라벨이 루프 본문에 나타날 수 있다는 점도 언급할 가치가 있다.

switch (i) {
  for (;;) {
    f();
  case 1:
    g();
  case 2:
    if (h()) break;
  }
}

좀 더 읽기 쉬운 문장이 있다면 이렇게 코드를 쓰지 말아주십시오만, 완벽하게 유효하며, 또 그 문구는 다음과 같다.f()통화할 수 있다

Duff's Device라는 유명한 용도가 있다.

int n = (count+3)/4;
switch (count % 4) {
  do {
    case 0: *to = *from++;
    case 3: *to = *from++;
    case 2: *to = *from++;
    case 1: *to = *from++;
  } while (--n > 0);
}

여기 다음에 가리키는 버퍼를 복사한다.from에 의해 지목된 완충액까지.to우리는 복사한다.count자료의 예

do{}while()첫 번째 진술 전에 진술이 시작된다.case, 라고 한다.case라벨은 에 내장되어 있다.do{}while().

이렇게 하면 끝의 조건부 분기 수가 줄어든다.do{}while()대략 4의 인수에 의해 마주치는 루프(이 예에서 상수는 원하는 값으로 조정될 수 있다).

이제, 최적화 도구들은 때때로 당신을 위해 이것을 할 수 있다(특히 그들이 스트리밍/벡터화된 지시를 최적화하고 있는 경우), 그러나 프로파일 안내 최적화 없이는 그들은 당신이 루프가 클 것으로 예상할지 아닐지 알 수 없다.

일반적으로 가변 선언은 그곳에서 발생할 수 있고 모든 경우에 사용될 수 있지만 스위치가 끝난 후에는 범위를 벗어난다.(초기화는 생략됨)

또한 스위치에 특유하지 않은 제어 흐름은 위에서 설명한 대로 스위치 블록의 해당 섹션으로 들어가거나goto.

Linux에서 gcc를 사용한다고 가정할 경우 4.4 이전 버전을 사용 중이면 경고가 표시되었을 것이다.

-Wunreachable 코드 옵션은 gcc 4.4에서 이후 제거되었다.

가변 선언뿐 아니라 선진 점프도 가능하다.스파게티 코드가 잘 맞지 않는 경우에만 잘 활용할 수 있다.

int main()
{
    int i = 1;
    switch(i)
    {
        nocase:
        printf("no case\n");

        case 0: printf("0\n"); break;
        case 1: printf("1\n"); goto nocase;
    }
    return 0;
}

인화

1
no case
0 /* Notice how "0" prints even though i = 1 */

스위치 케이스는 가장 빠른 제어 흐름 조항 중 하나라는 점에 유의해야 한다.그래서 프로그래머에게 매우 융통성이 있어야 하는데, 이런 경우는 가끔 있다.

유의해야 할 것은, 코드에 대한 구조적 제약이 사실상 없다는 점이다.switch진술서, 또는 어디에case *:라벨은 이 코드 안에 위치한다*.이는 더프의 장치와 같은 프로그래밍 기술을 가능하게 하며, 하나의 가능한 구현은 다음과 같다.

int n = ...;
int iterations = n/8;
switch(n%8) {
    while(iterations--) {
        sum += *ptr++;
        case 7: sum += *ptr++;
        case 6: sum += *ptr++;
        case 5: sum += *ptr++;
        case 4: sum += *ptr++;
        case 3: sum += *ptr++;
        case 2: sum += *ptr++;
        case 1: sum += *ptr++;
        case 0: ;
    }
}

알다시피, 그 사이의 암호는switch(n%8) {그리고case 7:라벨은 확실히 도달할 수 있다...


으로서 슈퍼 고양이 고맙게도 모두 발언에서 신통한 발언:지적했다*99이후 가진 정권 goto도 라벨(는 경우*:라벨이나 다르지 않)은 초저공 선언이 포함된 선언의 범위 내에 나타날 수 있다.그래서 이 사건의 배치에 대한 구조적 제한만:라벨이 말하는 것은 정확하지 않습니다.하지만, 궁둥이의 장비 VLA긴 달려 있지 않는 99표준을 앞당겼다.그럼에도 불구하고, 나는 이 때문에 제 첫번째 문장에"사실상"를 삽입할 필요성을 절감했다.

필수 옵션과 관련된 답변을 받으셨습니다. -Wswitch-unreachable경고를 생성하기 위해 이 답은 사용적합성/가치성 부분을 상세히 설명해야 한다.

에서 직접 인용하다.C11, 챕터 제6.8.4.2, ( 것 중)

switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}

식별자가 (블록 내에) 자동 저장 지속 기간으로 존재하지만 초기화되지 않는 개체, 따라서 제어 식이 0이 아닌 값을 갖는 경우 에 대한 호출printf함수는 불확실한 값에 접근할 것이다.마찬가지로, 함수에 대한 호출f손이 닿지 않다

그것은 매우 자기 설명적이다.이를 통해 에서만 사용할 수 있는 로컬 범위 변수를 정의할 수 있다.switch진술 범위

"루프 반"을 구현하는 것이 비록 최선의 방법은 아닐 수 있지만 가능하다.

char password[100];
switch(0) do
{
  printf("Invalid password, try again.\n");
default:
  read_password(password, sizeof(password));
} while (!is_valid_password(password));

참조URL: https://stackoverflow.com/questions/41727415/valid-but-worthless-syntax-in-switch-case

반응형