为什么 switch 语句需要中断?

给定一个简单的 switch 语句

switch (int)
{
case 1 :
{
printf("1\n");
break;
}


case 2 :
{
printf("2\n");
}


case 3 :
{
printf("3\n");
}
}

在情况2中没有 break 语句,这意味着在情况3的代码中将继续执行。 这不是意外,这是设计好的。为什么要做这样的决定?相对于为块提供自动中断语义,这样做有什么好处?理由是什么?

76435 次浏览

如果案件被设计成隐性破裂,那么你就不可能失败。

case 0:
case 1:
case 2:
// all do the same thing.
break;
case 3:
case 4:
// do something different.
break;
default:
// something else entirely.

如果这个开关被设计成在每个案件之后都隐含地爆发出来,你就没有选择了。开关箱结构的设计方法是更加灵活。

当多个用例需要执行相同的代码(或者按顺序执行相同的代码)时,它可以消除代码重复。

因为在汇编语言级别上,它并不关心是否在每个案例之间进行中断,反正秋季通过案例的开销是零,所以为什么不允许它们,因为它们在某些案例中提供了显著的优势。

Switch 语句中的 case 语句只是标签。

当您打开一个值时,switch 语句实际上对具有匹配值的标签执行 Goto操作。

这意味着必须使用中断来避免传递到下一个标签下的代码。

至于 为什么以这种方式实现的原因—— switch 语句的秋季通过性质在某些场景中可能是有用的。例如:

case optionA:
// optionA needs to do its own thing, and also B's thing.
// Fall-through to optionB afterwards.
// Its behaviour is a superset of B's.
case optionB:
// optionB needs to do its own thing
// Its behaviour is a subset of A's.
break;
case optionC:
// optionC is quite independent so it does its own thing.
break;

显然是为了实现达夫的设备:

dsend(to, from, count)
char *to, *from;
int count;
{
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7:      *to = *from++;
case 6:      *to = *from++;
case 5:      *to = *from++;
case 4:      *to = *from++;
case 3:      *to = *from++;
case 2:      *to = *from++;
case 1:      *to = *from++;
} while (--n > 0);
}
}

在很多方面,c 只是标准汇编习惯用法的一个干净的接口。在编写跳表驱动的流程控制时,程序员可以选择通过或跳出“控制结构”,而跳出需要显式的指令。

所以 C 也是这么做的。

正如这里许多人指定的那样,它允许单个代码块在多种情况下工作。与在示例中指定的“每种情况下代码块”相比,这种 应该在 switch 语句中更为常见。

如果每种情况下都有一个代码块而没有秋天,也许您应该考虑使用 If-elseif-else 块,因为这似乎更合适。

许多答案似乎集中在作为 原因要求 break语句的能力上。

我认为这只是一个错误,主要是因为在设计 C 时,对于如何使用这些构造几乎没有多少经验。

Peter Van der Linden 在他的书《专家 C 编程》中提出了这样的观点:

我们分析了 Sun C 编译器的源代码 看看违约率下降的频率 通过被使用。太阳 ANSI C 编译器前端有244开关 语句,每个语句都有一个 平均七个案子,通过 发生率只有3% 。

换句话说,正常的开关 行为是 错了97% 的时间。 它不仅存在于编译器中 相反,秋季通过使用 在这种分析中,通常是为了 更频繁发生的情况 在编译器中比在其他软件中, 例如,在编译运算符时 可以有一个或两个 操作数:

switch (operator->num_of_operands) {
case 2: process_operand( operator->operand_2);
/* FALLTHRU */


case 1: process_operand( operator->operand_1);
break;
}

案子的失败是如此普遍 被认为是一种缺陷 即使是一个特别的评论大会, 如上所示,它告诉 lint“这是 只有3% 的病例 希望落空。”

我认为对于 C # 来说,在每个 case 块的末尾都需要一个显式跳转语句是一个好主意(同时仍然允许多个 case 标签被堆叠——只要只有一个语句块)。在 C # 中,您仍然可以有一个情况下下降到另一个-您只需要使用 goto跳转到下一个情况,使秋季通过显式。

可惜 Java 没有利用这个机会来打破 C 语义。

允许这样的事情发生:

switch(foo) {
case 1:
/* stuff for case 1 only */
if (0) {
case 2:
/* stuff for case 2 only */
}
/* stuff for cases 1 and 2 */
case 3:
/* stuff for cases 1, 2, and 3 */
}

case关键字想象成一个 goto标签,它会自然得多。

我碰巧遇到了一个将向量中的值赋给结构的情况: 必须以这样一种方式来完成: 如果数据向量比结构中的数据成员数目短,其余的成员将保持其默认值。在这种情况下,省略 break是非常有用的。

switch (nShorts)
{
case 4: frame.leadV1    = shortArray[3];
case 3: frame.leadIII   = shortArray[2];
case 2: frame.leadII    = shortArray[1];
case 1: frame.leadI     = shortArray[0]; break;
default: TS_ASSERT(false);
}