在 switch case 语句中初始化数组
Initializing arrays in switch case statements
异想天开,我在 switch 语句中初始化了以下数组 c
完全期望我的编译器说 不,你不能那样做 但令我惊讶的是在 MSVC、GCC 和 Clang 中编译。在线example
我假设标准允许,在这种情况下我的问题是为什么? ...考虑到在 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;
};
}
你的阵列在原处完全没问题。您在 switch(ch)
的词法范围内声明(并初始化)它,允许它存在、被初始化并被其他操作引用(在声明之后)。
在 switch
之外引用它是行不通的,例如:
switch(ch) {
...
case 'z':
int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
};
some_operation(c);
唯一会被禁止的情况是,如果您有 另一个 case
语句使用相同的变量。由于 case
语句只是标签(正如 here 所指出的),您可以跳过稍后使用的变量的初始化。
因此,只要您仅在一个标签中使用该变量,而不是在多个标签中使用,编译器就会让您这样做。
如果跳转到 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:;
}
}
如果您将示例更改为
int main()
{
char ch;
switch( ch )
{
case 'x':
int c[2] = { 0 , 1 };
break;
case 'z':
int a = 42;
break;
}
}
您会注意到数组现在出现了错误,但 int
没有。
最后一种情况实际上允许初始化。
规则不是"you're not allowed to initialise a variable in a case
"而是"you're not allowed to jump across a variable initialisation."
并且在最后一种情况下不可能跳过初始化。
该规则的原因是在case
中声明的变量在后续情况的范围内,并且跳转到后续情况将绕过初始化。
如果你重写为 goto-sequence,这会变得(稍微)更清楚,因为关于范围和初始化的相同规则适用:
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:
异想天开,我在 switch 语句中初始化了以下数组 c
完全期望我的编译器说 不,你不能那样做 但令我惊讶的是在 MSVC、GCC 和 Clang 中编译。在线example
我假设标准允许,在这种情况下我的问题是为什么? ...考虑到在 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;
};
}
你的阵列在原处完全没问题。您在 switch(ch)
的词法范围内声明(并初始化)它,允许它存在、被初始化并被其他操作引用(在声明之后)。
在 switch
之外引用它是行不通的,例如:
switch(ch) {
...
case 'z':
int c[2] = { 0 , 1 }; // OKAY (Huh???)
break;
};
some_operation(c);
唯一会被禁止的情况是,如果您有 另一个 case
语句使用相同的变量。由于 case
语句只是标签(正如 here 所指出的),您可以跳过稍后使用的变量的初始化。
因此,只要您仅在一个标签中使用该变量,而不是在多个标签中使用,编译器就会让您这样做。
如果跳转到 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:;
}
}
如果您将示例更改为
int main()
{
char ch;
switch( ch )
{
case 'x':
int c[2] = { 0 , 1 };
break;
case 'z':
int a = 42;
break;
}
}
您会注意到数组现在出现了错误,但 int
没有。
最后一种情况实际上允许初始化。
规则不是"you're not allowed to initialise a variable in a case
"而是"you're not allowed to jump across a variable initialisation."
并且在最后一种情况下不可能跳过初始化。
该规则的原因是在case
中声明的变量在后续情况的范围内,并且跳转到后续情况将绕过初始化。
如果你重写为 goto-sequence,这会变得(稍微)更清楚,因为关于范围和初始化的相同规则适用:
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: