给出一个简单的switch语句
switch (int)
{
case 1 :
{
printf("1\n");
break;
}
case 2 :
{
printf("2\n");
}
case 3 :
{
printf("3\n");
}
}
在案例2中缺少break语句意味着在案例3的代码中将继续执行。 这不是意外;它是这样设计的。为什么做出这个决定?这提供了什么好处与块的自动中断语义?理由是什么?
答案 0 :(得分:145)
许多答案似乎都集中在原因要求break
声明的能力上。
我认为这只是一个错误,主要是因为在设计C时,对于如何使用这些结构的经验并不多。
Peter Van der Linden在他的“专家C编程”一书中提到了这个案例:
我们分析了Sun C编译器源代码 看看默认下降的频率 通过使用。太阳ANSI C 编译器前端有244个开关 声明,每个都有一个 平均7例。堕落 仅发生在所有这些案件中的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语义。
答案 1 :(得分:30)
在很多方面,c只是标准装配惯用语的干净界面。在编写跳转表驱动的流控制时,程序员可以选择通过或跳出“控制结构”,跳出需要一个明确的指令。
所以,c做同样的事情......
答案 2 :(得分:21)
显然要实现Duff的设备:
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);
}
}
答案 3 :(得分:18)
如果案件被设计为隐含破坏,那么你就无法实现这一目标。
case 0:
case 1:
case 2:
// all do the same thing.
break;
case 3:
case 4:
// do something different.
break;
default:
// something else entirely.
如果开关设计为在每个案例后隐式突破,您将无法选择它。开关盒结构的设计方式更加灵活。
答案 4 :(得分:15)
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;
答案 5 :(得分:8)
允许以下内容:
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
标签,它更自然地来了。
答案 6 :(得分:3)
当几个案例需要执行相同的代码(或顺序相同的代码)时,它消除了代码重复。
由于在汇编语言级别上,它并不关心你是否在每一个之间断开,因此无论如何都会出现零开销,所以为什么不允许它们,因为它们在某些情况下具有显着优势。
答案 7 :(得分:2)
我碰巧遇到了将向量中的值分配给结构的情况:必须以这种方式完成:如果数据向量短于结构中数据成员的数量,则其余成员将保留其默认值。在那种情况下,省略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);
}
答案 8 :(得分:0)
正如许多人在此指定的那样,允许单个代码块适用于多种情况。对于您的switch语句,应该更常见,而不是您在示例中指定的“每个案例的代码块”。
如果每个案例都有一个代码块而没有漏掉,也许您应该考虑使用if-elseif-else块,因为这似乎更合适。