【问题标题】:Initializing arrays in switch case statements在 switch case 语句中初始化数组
【发布时间】:2016-05-12 15:55:10
【问题描述】:

奇怪的是,我在一个 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;
    };
}

【问题讨论】:

  • 您为什么希望编译器不喜欢这样? cswitch(ch) 的上下文中完全有效,但在外部不可见。
  • 定义(本地)和初始化数组是可以的,但是您将无法在switch 范围之外使用它...(int a = 42; 也应该可以正常工作)(。 .. 没有理由在这里标记 C++)
  • 这只是一个 MWE。我打算在case语句中使用c
  • @AlexLop。这个问题涉及到 C 和 C++

标签: c++ c arrays initialization switch-statement


【解决方案1】:

如果您将示例更改为

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:

【讨论】:

    【解决方案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:;
        }       
    }    
    

    【讨论】:

    • goto 的好例子!我明白委员会的意图是防止跳过初始化,但它不是防弹的,因为不禁止跳过延迟初始化。
    【解决方案3】:

    你的数组在哪里完全没问题。您在 switch(ch) 的词法范围内声明(和初始化)它,允许它在其中存在、被初始化并被其他操作引用(在声明之后)。

    switch 之外引用它是行不通的,就像这样:

    switch(ch) {
      ...
      case 'z':
        int c[2] = { 0 , 1 };  // OKAY (Huh???)
        break;
    };
    
    some_operation(c);
    

    唯一会被禁止的情况是,如果您有 另一个 case 使用相同变量的语句。由于case 语句只是标签(正如here 指出的那样),您可能会跳过稍后使用的变量的初始化。

    所以,编译器让你这样做,只要你只在一个标签中使用变量,而不是多个标签。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2014-01-06
      • 2013-09-24
      相关资源
      最近更新 更多