약간의 오타를 통해 실수 로이 구성을 찾았습니다.
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
도달 할 수 없습니다.
PS BTW, 샘플이 유효한 C ++ 코드가 아닙니다. 이 경우 ( N4140 6.7/3
, 강조 광산) :
변수가 스칼라 유형 , 사소한 기본 생성자가있는 클래스 유형 및 사소한 소멸자를 갖지 않는 한, 자동 저장 기간이있는 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 90 이 점프하는 프로그램 은 , 이러한 유형 중 하나의 cv 규정 버전 또는 이전 유형 중 하나의 배열이며 초기화 프로그램 (8.5) 없이 선언됩니다 .
90)
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 이하 버전을 사용하는 경우 경고 메시지가 표시됩니다.
답변
변수 선언뿐만 아니라 고급 점프도 가능합니다. 스파게티 코드를 사용하지 않는 경우에만 잘 활용할 수 있습니다.
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는 가장 빠른 제어 흐름 절 중 하나입니다. 따라서 프로그래머에게 매우 유연해야하며 때로는 이와 같은 경우가 포함됩니다.
답변
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:
레이블 사이의 코드에 도달 할 수 있습니다.
* 으로 supercat 고맙게도 코멘트 지적 : C99,도 때문에 goto
나 라벨이 (그것을 할 수 case *:
VLA 선언을 포함하는 선언의 범위 내에서 나타날 수 라벨 없음). 따라서 레이블 배치에 구조적 제한 이 없다고 말하는 것은 올바르지 않습니다 case *:
. 그러나 더프의 장치는 C99 표준보다 오래되었으며 VLA에 의존하지 않습니다. 그럼에도 불구하고, 나는 이것 때문에 첫 문장에 “가상”을 삽입해야한다는 느낌이 들었다.
답변
경고를 생성 하는 데 필요한 gcc
옵션 과 관련된 답변을 얻었습니다 -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); }
식별자가
i
자동 저장 기간 (블록 내)으로 존재하지만 초기화되지 않는 객체 이므로 제어 표현식에 0이 아닌 값이 있으면printf
함수에 대한 호출이 결정 되지 않은 값에 액세스합니다. 마찬가지로 함수 호출에f
도달 할 수 없습니다.
매우 설명이 필요합니다. 이를 사용하여 switch
명령문 범위 내에서만 사용 가능한 로컬 범위 변수를 정의 할 수 있습니다 .