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

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

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

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

以上给出了以下错误(MSC):

“newVal”的初始化由“case”标签跳过

在其他语言中,这似乎也是一个限制。为何会出现这样的问题呢?


慕斯709654
浏览 791回答 3
3回答

呼啦一阵风

Case陈述仅限于标签..这意味着编译器将解释为直接跳转到标签。在C+中,这里的问题是范围问题之一。您的花括号将作用域定义为switch声明。这意味着您将有一个范围,在该范围内,将在代码中执行跳转,跳过初始化。正确的处理方法是定义一个特定于case语句,并在其中定义变量。switch (val){   case VAL:  {   // This will work   int newVal = 42;     break;}case ANOTHER_VAL:  ...break;}

30秒到达战场

这个问题是最初被标记为[C]和[C+]。原来的代码在C和C+中都是无效的,但是由于完全不同的原因。我相信这个重要的细节被现有的答案所遗漏(或混淆)。在C+中,此代码无效,因为case ANOTHER_VAL:标签跳入变量的范围。newVal绕过它的初始化。跳过本地对象的初始化在C+中是非法的。大多数答案都正确地处理了这个问题的这一面。但是,在C语言中,绕过变量初始化并不是一个错误。在初始化时跳入变量的范围在C中是合法的。它只是意味着变量没有初始化。由于完全不同的原因,原始代码没有在C中编译。标签case VAL:在原始代码中,变量的声明附加在一起。newVal..在C语言中,声明不是语句。他们不能被贴上标签。当这段代码被解释为C代码时,这就是导致错误的原因。switch&nbsp;(val)&nbsp;&nbsp;{&nbsp;&nbsp;case&nbsp;VAL:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;<-&nbsp;C&nbsp;error&nbsp;is&nbsp;here&nbsp;*/ &nbsp;&nbsp;int&nbsp;newVal&nbsp;=&nbsp;42;&nbsp;&nbsp; &nbsp;&nbsp;break;case&nbsp;ANOTHER_VAL:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;<-&nbsp;C++&nbsp;error&nbsp;is&nbsp;here&nbsp;*/ &nbsp;&nbsp;... &nbsp;&nbsp;break;}加一个额外的{}块修复了C+和C两个问题,尽管这些问题恰好不同。在C+方面,它限制了newVal,确保case ANOTHER_VAL:不再跳入该范围,从而消除了C+问题。在C边那额外的{}引入复合语句,从而使case VAL:标签可应用于语句,从而消除了C问题。在C情况下,这个问题可以很容易地解决,而不需要{}..之后添加一个空语句即可。case VAL:标签和代码将变得有效。switch&nbsp;(val)&nbsp;&nbsp;{&nbsp;&nbsp;case&nbsp;VAL:;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Now&nbsp;it&nbsp;works&nbsp;in&nbsp;C!&nbsp;*/ &nbsp;&nbsp;int&nbsp;newVal&nbsp;=&nbsp;42;&nbsp;&nbsp; &nbsp;&nbsp;break;case&nbsp;ANOTHER_VAL:&nbsp;&nbsp; &nbsp;&nbsp;... &nbsp;&nbsp;break;}注意,尽管从C的角度来看,它现在是有效的,但从C+的角度来看,它仍然是无效的。对称地说,在C+情况下,这个问题可以很容易地解决,而不需要{}..只要从变量声明中删除初始化程序,代码就会生效。switch&nbsp;(val)&nbsp;&nbsp;{&nbsp;&nbsp;case&nbsp;VAL:&nbsp; &nbsp;&nbsp;int&nbsp;newVal; &nbsp;&nbsp;newVal&nbsp;=&nbsp;42;&nbsp;&nbsp; &nbsp;&nbsp;break;case&nbsp;ANOTHER_VAL:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Now&nbsp;it&nbsp;works&nbsp;in&nbsp;C++!&nbsp;*/ &nbsp;&nbsp;... &nbsp;&nbsp;break;}注意,尽管从C+的角度来看,它现在是有效的,但从C的角度来看,它仍然是无效的。

Qyouu

好的。严格地澄清这一点与声明无关。它只涉及“跳过初始化”(ISO C+‘03 6.7/3)这里的许多帖子提到,跳过声明可能会导致变量“未声明”。这不是真的。POD对象可以在没有初始化器的情况下被声明,但是它有一个不确定的值。例如:switch&nbsp;(i){ &nbsp;&nbsp;&nbsp;case&nbsp;0: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;j;&nbsp;//&nbsp;'j'&nbsp;has&nbsp;indeterminate&nbsp;value &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j&nbsp;=&nbsp;0;&nbsp;//&nbsp;'j'&nbsp;initialized&nbsp;to&nbsp;0,&nbsp;but&nbsp;this&nbsp;statement &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;is&nbsp;jumped&nbsp;when&nbsp;'i&nbsp;==&nbsp;1' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;case&nbsp;1: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++j;&nbsp;&nbsp;&nbsp;//&nbsp;'j'&nbsp;is&nbsp;in&nbsp;scope&nbsp;here&nbsp;-&nbsp;but&nbsp;it&nbsp;has&nbsp;an&nbsp;indeterminate&nbsp;value &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;}如果对象是非POD或聚合,编译器将隐式添加初始化器,因此不可能跳过这样的声明:class&nbsp;A&nbsp;{public: &nbsp;&nbsp;A&nbsp;();};switch&nbsp;(i)&nbsp;&nbsp;//&nbsp;Error&nbsp;-&nbsp;jumping&nbsp;over&nbsp;initialization&nbsp;of&nbsp;'A'{ &nbsp;&nbsp;&nbsp;case&nbsp;0: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;j;&nbsp;&nbsp;&nbsp;//&nbsp;Compiler&nbsp;implicitly&nbsp;calls&nbsp;default&nbsp;constructor &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; &nbsp;&nbsp;&nbsp;case&nbsp;1: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;}此限制不限于开关语句。使用“goto”跳过初始化也是一个错误:goto&nbsp;LABEL;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Error&nbsp;jumping&nbsp;over&nbsp;initializationint&nbsp;j&nbsp;=&nbsp;0;&nbsp;LABEL: &nbsp;&nbsp;;有一点需要注意的是,这是C+和C之间的区别,在C中,跳过初始化并不是一个错误。正如其他人所提到的,解决方案是添加一个嵌套块,以便变量的生存期仅限于个别的CASE标签。
打开App,查看更多内容
随时随地看视频慕课网APP