没有case的switch语句

22
今天,我偶然发现我的编译器在没有case语句的情况下写代码时并不会报错。(它会抱怨缺少case语句,但在代码后添加一个case语句后,竟然没有任何警告来告诉我代码是无用的。)
我正在努力弄清楚允许以下代码是否有目的,还是只是那种“限制它更麻烦,所以允许”的事情之一。
#include <iostream>
void foo() {
   std::cout << "foo" << std::endl;
}
 
int main()
{
   for (int a = -10; a < 10; ++a)
   {
      switch(a)
      {
         foo();
      case 4:
         std::cout << "4" << std::endl;
      }
   }
}

这个现在输出"4",当a == 4时,正如预期的那样,它从来没有输出foo。所以问题是,是否有一些(潜在的,但有用的)原因允许在第一个case之前有foo();这样的语句?我确定我不能在那里声明和初始化变量。
顺便说一下,我已经在MSVC 2012和GCC 4.8.1上进行了测试,它们产生了相同的行为。令人惊讶的是,它们也都没有输出警告。
我还尝试了带有-Wall的gcc。在一个古老版本的GCC(AIX上的3.3.2)上,我得到了一个无法到达的代码警告。在一个更近期的版本(Cygwin上的4.5.3)上,我没有收到警告。

2
这是什么编译器? - turnt
我已在MSVC 2012和GCC 4.8.1上进行了测试。 - Shirik
嗯,有趣。脑海中浮现出一个想法,就是不必写default:,而只需在最后一个case下面编写代码。但是,这可能会引起潜在的不良实践 :) - Paul Renton
你尝试过在GCC中使用“-Wall”吗? - Fred Larson
好的,我尝试了-Wall。在一个古老版本的GCC(AIX上的3.3.2)上,我收到了一个无法访问代码警告。在一个更近期的版本(Cygwin上的4.5.3),我没有收到任何警告。 - Fred Larson
2个回答

9
是的,这种行为是语言设计上的,你可以在不同的位置添加代码。Switch语句比看起来复杂得多,它们允许编写相当奇怪的代码,无论是否合理。
如果您想花些时间研究一些奇怪的switch用法和case的位置,可以查看boost asio库中协程的实现。您可以使用宏编写一个小函数,编译并查看生成的代码(经过宏扩展后)的样子。

Boost的实现通常让我感到害怕,但现在你引起了我的好奇心。 - Shirik
5
@Shirik,switch-sorcery 的经典例子是 Duff's device:一个与 do-while 循环缠绕在一起的 switch 语句。 - TemplateRex
被快速解决了。很高兴有人提到了达夫设备。我(很少)在嵌入式系统上使用这种巫术来分解长函数并使它们更容易重新启动。但是,如果您在使用“goto”时感到不舒服,那么在使用此类入口点之前应该特别注意是否使用开关。 - Speed8ump
3
没有回答 OP 的问题,也不够具体。 - abetancort

4

来自MSDN的解释:

声明可以出现在形成switch主体的复合语句的头部,但是声明中包含的初始化不会被执行。switch语句将控制直接传递到主体内的可执行语句,绕过包含初始化的行。


3
如果必须要说一个“源”,我不会称 MSDN 为“源”,如果非要选一个,那标准应该是“唯一的源”。 - David Rodríguez - dribeas
是的,我确实看了一下C++标准,但没有深入了解。我只是证明了似乎没有任何限制它的东西。这更像是那种“由于缺乏规则而允许”的事情。 - Shirik
@MadScienceDreams:这是非法的,因为 case 语句绕过了 x 的初始化。 - Shirik
1
@Shirik 啊,看错了,仍然不明白允许这段代码的意义。 - IdeaHat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接