문 에서 {
및 사용의 요점은 무엇입니까 ? 일반적으로 명령문 에 몇 줄이 있더라도 모든 줄이 실행됩니다. 이것은 단지 구형 / 최신 컴파일러에 관한 규칙입니까, 아니면 그 뒤에 뭔가가 있습니까?}
case
case
int a = 0;
switch (a) {
case 0:{
std::cout << "line1\n";
std::cout << "line2\n";
break;
}
}
과
int a = 0;
switch (a) {
case 0:
std::cout << "line1\n";
std::cout << "line2\n";
break;
}
답변
는 {}
새로운 블록 나타낸다 범위 .
다음과 같은 매우 인위적인 예를 고려하십시오.
switch (a)
{
case 42:
int x = GetSomeValue();
return a * x;
case 1337:
int x = GetSomeOtherValue(); //ERROR
return a * x;
}
x
범위에 이미 정의되어 있기 때문에 컴파일러 오류가 발생 합니다.
이를 자체 하위 범위로 분리 x
하면 switch 문 외부에서 선언 할 필요가 없습니다 .
switch (a)
{
case 42: {
int x = GetSomeValue();
return a * x;
}
case 1337: {
int x = GetSomeOtherValue(); //OK
return a * x;
}
}
답변
TL; DR
이니셜 라이저 또는 케이스 내에서 사소하지 않은 개체를 사용하여 변수를 선언 할 수있는 유일한 방법 은 루프 또는 if 문과 같은 자체 범위가있는 다른 제어 구조를 사용하여 블록 범위 를 도입하는 {}
것 입니다.
피투성이 세부 사항
우리는 볼 수있는 경우가 바로되어 제표 표시 등 라벨 와 함께 사용 고토 문 ( 이은으로 덮여 표준 초안 C ++ 6.1 레이블 문 ) 우리는 절에서 볼 수있는 6.7
제 3 많은 경우에 허용되지 않습니다 점프 선언을 통과하는 것이 , 초기화 포함 :
블록으로 전송할 수 있지만 초기화를 통해 선언을 우회하는 방식은 아닙니다. 자동 저장 기간이있는 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 87 을 점프하는 프로그램 은 변수에 스칼라 유형, 사소한 기본 생성자가있는 클래스 유형 및 사소한 소멸자가 없으면 형식이 잘못되었습니다. 이 유형 중 하나의 cv 규정 버전 또는 이전 유형 중 하나의 배열이며 이니셜 라이저없이 선언됩니다 (8.5).
이 예제를 제공합니다.
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor
// call for a followed by construction
// again immediately following label ly
}
여기에는 몇 가지 미묘한 점이 있습니다. 초기화가없는 스칼라 선언 을 건너 뛸 수 있습니다. 예를 들면 다음과 같습니다.
switch( n )
{
int x ;
//int x = 10 ;
case 0:
x = 0 ;
break;
case 1:
x = 1 ;
break;
default:
x = 100 ;
break ;
}
완벽하게 유효합니다 ( 라이브 예제 ). 물론 각 경우에 동일한 변수를 선언하려면 각각 고유 한 범위가 필요하지만 switch 문 외부에서도 동일한 방식으로 작동 하므로 큰 놀라지 않아야합니다.
초기화를 넘어서 점프를 허용하지 않는 이유에 대해서는 약간 다른 문제를 다루지 만 결함 보고서 467 은 자동 변수에 대한 합리적인 사례를 제공 합니다 .
[…] 자동 변수는 명시 적으로 초기화되지 않은 경우 트랩 표현을 포함하여 불확실한 ( “가비지”) 값을 가질 수 있습니다. […]
스위치 내에서 범위 를 여러 경우로 확장하는 경우를 살펴 보는 것이 더 흥미로울 것입니다 . 가장 유명한 예는 다음과 같은 Duff의 장치 일 것입니다 .
void send( int *to, const int *from, int count)
{
int n = (count + 7) / 8;
switch(count % 8)
{
case 0: do { *to = *from++; // <- Scope start
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); // <- Scope end
}
}
답변
결과 소멸자 (또는 범위 충돌)가있는 변수 선언을 case
절 에 삽입 할 수있는 습관입니다 . 그것을 보는 또 다른 방법은 그들이 원하는 언어로 작성하는 것입니다. 모든 흐름 제어는 문장의 시퀀스가 아니라 블록으로 구성됩니다.
답변
이것이 기본적인 컴파일러 제한인지 확인하면 무슨 일이 일어나는지 궁금해 할 것입니다.
int c;
c=1;
switch(c)
{
case 1:
//{
int *i = new int;
*i =1;
cout<<*i;
break;
//}
default : cout<<"def";
}
그러면 오류가 발생합니다.
error: jump to case label [-fpermissive]
error: crosses initialization of ‘int* i’
이것은 다음을 수행하지 않습니다.
int c;
c=1;
switch(c)
{
case 1:
{
int *i = new int;
*i =1;
cout<<*i;
break;
}
default : cout<<"def";
}
답변
스위치에서 대괄호를 사용하는 것은 Rotem이 말한 것처럼 새로운 범위 블록을 나타냅니다.
그러나 읽을 때 명확하게 할 수도 있습니다. 조건부 중단이있을 수 있으므로 케이스가 중지되는 위치를 파악합니다.
답변
이유는 다음과 같습니다.
- 가독성, 범위가 지정된 섹션으로 각 사례를 시각적으로 향상시킵니다.
- 여러 스위치 케이스에 대해 동일한 이름으로 다른 변수를 선언합니다.
- 마이크로 최적화-케이스의 범위를 벗어나 자마자 파괴하려는 정말 값 비싼 리소스 할당 변수의 범위 또는 “GOTO”명령 사용에 대한 더 스파게티 시나리오.