奇怪的是,我在一个switch语句中初始化了以下数组c
,完全期望我的编译器说 NO你不能那样做但令我惊讶的是它编译在MSVC,GCC中和Clang。在线{{3}}
我假设标准允许它,在这种情况下我的问题是为什么? ...考虑到case语句中不允许声明和初始化非数组。
int main()
{
char ch;
switch( ch )
{
case 'x':
//int a = 42; // NOT OKAY
break;
case 'y':
int b;
b = 42; // OKAY
case 'z':
int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
};
}
答案 0 :(得分:6)
如果您将示例更改为
int main()
{
char ch;
switch( ch )
{
case 'x':
int c[2] = { 0 , 1 };
break;
case 'z':
int a = 42;
break;
}
}
你会注意到数组现在出现了错误,但int
却没有。
最后一种情况实际上允许使用初始化。
规则不是“你不允许在case
中初始化变量”,而是“你不允许跳过变量初始化。”
在最后一种情况下,跳过初始化是不可能的。
规则的原因是在case
中声明的变量在后续情况下属于范围,跳转到后续情况会绕过初始化。
如果你重写为goto序列,这会变得(略微)更清晰,因为关于范围和初始化的相同规则适用:
if (ch == 'x') goto x;
if (ch == 'y') goto y;
if (ch == 'z') goto z;
goto end;
{
x:
int a = 42; // goto y or z breaks this
goto end;
y:
int b; // uninitialised, so OK
b = 42;
goto end;
z:
int c[2] = {0, 1}; // No label after this, so can't jump across, so OK
goto end;
}
end:
答案 1 :(得分:2)
如果跳转到case标签绕过初始化的数组,编译器将发出错误。例如
switch( ch )
{
int c[2] = { 0 , 1 }; // OKAY (Huh???)
case 'x':
//int a = 42; // NOT OKAY
break;
case 'y':
int b;
b = 42; // OKAY
case 'z':
// int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
}
或
switch( ch )
{
case 'x':
//int a = 42; // NOT OKAY
break;
case 'y':
int b;
b = 42; // OKAY
case 'z':
int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
default:
break;
}
但是在原始程序中,两个跳转都不会绕过初始化的数组。
这是一个更简化的示范程序。 这将成功编译
int main()
{
goto L1;
{
L1:;
int c[2] = { 0 , 1 };
}
}
虽然这会发出错误
int main()
{
goto L1;
{
int c[2] = { 0 , 1 };
L1:;
}
}
答案 2 :(得分:0)
你的阵列完全没问题。您在switch(ch)
的词法范围内声明(并初始化)它,允许它存在,被初始化,并被其他操作引用(在声明之后)。
在switch
之外引用它的行为是不可行的,如下所示:
switch(ch) {
...
case 'z':
int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
};
some_operation(c);
如果您使用另一个使用相同变量的 case
语句,则禁止此操作的唯一情况是。由于case
语句只是标签(如指出here),因此您可能只是跳过后续使用变量的初始化。
所以,只要你只在一个标签中使用变量,编译器就可以这样做,但不是多个。