为什么不能在switch语句中声明变量?

我一直在想这个 - 为什么你不能在switch语句的case标签后面声明变量? 在C ++中,你可以在任何地方声明变量(并且声明它们接近第一次使用显然是一件好事),但以下内容仍然不起作用:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

以上给我以下错误(MSC):

'newVal'的初始化由'case'标签跳过

这似乎也是其他语言的限制。 为什么会出现这样的问题?


Case陈述只是标签 。 这意味着编译器会将其解释为直接跳转到标签。 在C ++中,这里的问题是范围之一。 您的大括号将范围定义为switch语句内的所有内容。 这意味着你只剩下一个范围,在该范围内跳过代码进一步执行跳过初始化的代码。 处理这种情况的正确方法是定义特定于该case语句的范围并在其中定义您的变量。

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}

这个问题同时被标记为[C]和[C ++]。 原始代码在C和C ++中都是无效的,但是完全不同的不相干的原因。 我相信这个重要的细节被现有的答案遗漏了(或混淆了)。

  • 在C ++中,这个代码是无效的,因为case ANOTHER_VAL: label跳转到变量newVal的范围,绕过了它的初始化。 跳过本地对象的初始化在C ++中是非法的。 大多数答案正确解决了这个问题的这一方面。

  • 但是,在C语言中,绕过变量初始化不是错误。 在初始化时跳入变量的范围在C中是合法的。它仅表示该变量未被初始化。 出于完全不同的原因,原始代码不能在C中编译。 标签case VAL:在原始代码中附加到变量newVal的声明中。 在C语言中,声明不是语句。 他们不能被贴上标签。 当这段代码被解释为C代码时,这就是导致错误的原因。

    switch (val)  
    {  
    case VAL:             /* <- C error is here */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:     /* <- C++ error is here */
      ...
      break;
    }
    
  • 添加一个额外的{}块可以修复C ++和C两个问题,即使这些问题发生了很大的变化。 在C ++方面,它限制了newVal的范围,确保这种case ANOTHER_VAL:不再跳入该范围,从而消除了C ++问题。 在额外的{}引入复合语句的C方面,因此使得应用于语句的case VAL: label消除了C问题。

  • 在C情况下,如果没有{} ,问题很容易解决。 在case VAL: label和代码将变为有效之后,只需添加一个空语句

    switch (val)  
    {  
    case VAL:;            /* Now it works in C! */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:  
      ...
      break;
    }
    

    请注意,即使从C的角度来看它现在是有效的,但从C ++的角度来看它仍然是无效的。

  • 对称地,在C ++的情况下,如果没有{} ,问题可以很容易地解决。 只需从变量声明中删除初始化程序,代码将变为有效

    switch (val)  
    {  
    case VAL: 
      int newVal;
      newVal = 42;  
      break;
    case ANOTHER_VAL:     /* Now it works in C++! */
      ...
      break;
    }
    

    请注意,即使从C ++的角度来看它现在是有效的,但从C的角度来看,它仍然是无效的。


  • 好。 只是为了澄清这与声明严格无关。 它只涉及“跳过初始化”(ISO C ++ '03 6.7 / 3)

    这里的很多帖子都提到跳过声明可能会导致变量“未声明”。 这不是真的。 POD对象可以在没有初始化器的情况下声明,但是它会有一个不确定的值。 例如:

    switch (i)
    {
       case 0:
         int j; // 'j' has indeterminate value
         j = 0; // 'j' initialized to 0, but this statement
                // is jumped when 'i == 1'
         break;
       case 1:
         ++j;   // 'j' is in scope here - but it has an indeterminate value
         break;
    }
    

    在对象是非POD或聚集的情况下,编译器隐式地添加了一个初始化器,因此不可能跳过这样的声明:

    class A {
    public:
      A ();
    };
    
    switch (i)  // Error - jumping over initialization of 'A'
    {
       case 0:
         A j;   // Compiler implicitly calls default constructor
         break;
       case 1:
         break;
    }
    

    此限制不限于switch语句。 使用'goto'跳过初始化也是一个错误:

    goto LABEL;    // Error jumping over initialization
    int j = 0; 
    LABEL:
      ;
    

    有点琐事,这是C ++和C之间的区别。在C中,跳过初始化不是错误。

    正如其他人所提到的,解决方案是添加一个嵌套块,以便变量的生存期限于个别情况标签。

    链接地址: http://www.djcxy.com/p/273.html

    上一篇: Why can't variables be declared in a switch statement?

    下一篇: How do I detect a click outside an element?