为什么case语句中的标签应该是常量



在JavaScript中,以下语句是有效的。

switch(true) {
case a > b:
max = a;
break;
case a < b:
max = b;
break;
default:
max = a;
}

但在C/C++编程语言中,当我编写此语句时,编译器会给我一个错误,显示case语句必须由常数值组成。有时在特定情况下,编写这样的switchcase语句会非常有用,但C/C++不允许我这样做

现在我很想知道,不允许在case语句中使用变量值背后的意义是什么?

C++是从C进化而来的,其中switch语句被认为是一个跳转表(分支表)。要实现为跳转表,切换条件应该是恒定的,这样就可以很容易地将其转换为标签。

尽管标准从来没有规定switch语句应该如何实现,但最重要的是,case标签应该是这样的,以便在编译时对其进行评估。在C和C++中,switch语句计算表达式,并将控制权转移到计算条件表达式值的多个case语句值之一。

6.4.2切换语句[stmt.switch]

switch语句会根据条件的值将控制权转移到多个语句中的一个。

这种行为使它不同于其他支持条件in case语句的语言。

对于一个实例,Javascript将switch ... case语句描述为

MDN交换机

switch语句计算表达式,将表达式的值与case子句匹配,并执行与该case关联的语句。

所以您实际上是在尝试比较两种不同的构造,并期望行为是相同的

至于答案the point behind this to not allowing variable values to be used in case statements?,这将使switch .. case成为一个效率较低的构造,其中对于每个迭代/实例,都应该重新评估事例标签,以确定它是否与条件表达式匹配。

C(而不是C++)标准说:

C11:6.8.4.2切换语句(p3)

每个case标签的表达式应为整数常量表达式,并且同一switch语句中的两个case常量表达式在转换后都不应具有相同的值。[…]

如果case中允许表达式,那么两个表达式可能具有相同的值。

C++(而不是C)标准也这么说:

C++11:6.4.2第2段:

[…]在转换为开关条件的提升类型后,同一开关中的两个case常量都不应具有相同的值。

switch/case之所以存在(请记住,if/else适用于其他所有内容),是为了为较低级别的"跳转"语法提供一个模拟,以便您可以为代码创建快速、静态的"跳转表"。如果允许运行时表达式,那么这个原因就消失了。

为什么switch做这件事类似于问if为什么做另一件事,因此是空洞的。

仅仅因为你能做某事并不意味着这是有意义的。特别地,switch并不等同于if/else梯形图。

if/elseswitch更通用,后者旨在"根据开关表达式的值选择要做的事情"。

练习-下面的代码会做什么?

var a = 5;
var b = 0;
switch(a)
{
case 5: b = 1; break;
case 5: b = 2; break;
case 1: b = 3; break;
}

现在b等于2还是1?如果它同时执行两个分支,则不会执行"选择一件要执行的事情",如果它执行其中一件而不执行另一件,则是任意决定。

将大小写值限制为常量表达式允许编译器对此代码发出错误。如果运行时的值可能不同,则编译器无法验证两种情况是否具有相同的值,这是Halting问题的结果。

最新更新