关于c ++:Switch中不正确的多个案例不会产生编译器错误


Incorrect Multiple Cases in Switch not generating compiler error

本问题已经有最佳答案,请猛点这里访问。

我知道这个代码不能按"预期"工作。只要快速查看这段代码,我们认为返回值应该是1,但在执行过程中返回3。

1
2
3
4
5
6
7
8
9
10
11
// incorrect
variable = 1;
switch (variable)
{
  case 1, 2:
    return 1;
  case 3, 4:
    return 2;
  default:
    return 3;
}

还有一些正确的选择:

1
2
3
4
5
6
7
8
9
10
11
// correct 1
variable = 1;
switch (variable)
{
  case 1: case 2:
    return 1;
  case 3: case 4:
    return 2;
  default:
    return 3;
}

1
2
3
4
5
6
7
8
9
10
11
12
// correct 2
switch (variable)
{
  case 1:
  case 2:
    return 1;
  case 3:
  case 4:
    return 2;
  default:
    return 3;
}

在开关中的多个情况下,这是部分答案:

我想知道为什么不正确的形式编译没有错误,甚至警告(至少在Borland C++编译器)。

编译器在代码中理解什么?


Just looking quickly at this code, we think the return value should be 1,

我会说,一个有经验的C++开发人员会立即注意到一些错误,并很快得出结论,其他程序员意外尝试使用逗号运算符:EDCOX1,16。

but in the execution it returns returns 3.

不,代码不能编译,因为case表达式不是常量

事实上,它不在任何半现代的编译器中编译。例如,MSVC 2013表示:

1
2
stackoverflow.cpp(8) : error C2051: case expression not constant
stackoverflow.cpp(10) : error C2051: case expression not constant

1, 2这样的表达式是逗号运算符的应用程序,逗号运算符意味着表达式不是编译时常量。

至少直到C++ 11出现,并放宽规则的效果,即添加括号,即EDCOX1〔18〕,将被允许编译。它不会像你想象的那样。

This is partially answered in Multiple Cases in Switch:

怎么会这样?另一个问题和答案几乎完全是关于C++的,而不是C++。

I would like to know why the incorrect form does compile without error
or event warnings (at least in the Borland C++ compiler).

因为编译器太旧了。最好换一个新的。


EDCOX1·4是C和C++中的一个有效表达式。意思是"评估a,放弃,评估b"。表达式的值是b。所以你原来的switch有如下含义:

1
2
3
4
5
6
7
8
9
10
variable = 1;
switch(variable)
{
  case 2:
    return 1;
  case 4:
    return 2;
  default:
    return 3;
}

关于逗号操作符的更多信息,您可以阅读维基百科的文章。


我的猜测是,在第一种情况下,编译器对逗号运算符进行计算,以使代码执行如下:

1
2
3
4
5
6
7
8
9
switch(variable)
{
  case 2:
    return 1;
  case 4:
    return 2;
  default:
    return 3;
}

从上面可以看出为什么输入1返回值3。我建议你读一下逗号运算符。上面有一些与之相关的优秀线程。


形式a, b的表达式具有值b。这就是逗号运算符的工作原理。

从表面上看,case 1, 2:相当于case 2:等。

但是,case标签必须是常数整型表达式,EDCOX1 OR 0Ω不是常数表达式,因为它包含逗号运算符(C++语法规定常量表达式不能包含逗号运算符)。因此,编译器应该发出一个错误。

您经常会看到case 1: case 2:,由于switch的后续行为,它将允许在1和2个案例中运行该行后面的语句。


做些实验。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int test(int variable) {
  switch (variable)
  {
    case 1, 2:
      return 1;
    case 3, 4:
      return 2;
    default:
      return 3;
  }
}

int main(void) {
  int i;

  for (i = 1; i <= 5; i++)
  {
    printf("%d -> %d
"
, i, test(i));
  }
  return 0;
}

用Borland C++5.5.1编译的Win32,输出为

1
2
3
4
5
1 -> 3
2 -> 1
3 -> 3
4 -> 2
5 -> 3

说明1, 2被解释为23, 4被解释为4


在C或C++中,逗号表达式具有以下规则:

  • 从左到右操作。
  • 逗号表达式的值是最后一个表达式的值。
  • 所以代码case 1,2:等于case 2:,因为逗号表达式的值为2。