给出一个简单的switch语句
switch (int) { case 1 : { printf("1\n"); break; } case 2 : { printf("2\n"); } case 3 : { printf("3\n"); } }
在案例2中没有break语句意味着在案例3的代码中将继续执行.这不是偶然的; 它是这样设计的.为什么做出这个决定?这提供了什么好处与块的自动中断语义?理由是什么?
许多答案似乎都集中在作为要求声明的理由而失败的能力break
.
我认为这只是一个错误,主要是因为在设计C时,对这些结构的使用方式几乎没有多少经验.
Peter Van der Linden在他的"专家C编程"一书中提到了这个案例:
我们分析了Sun C编译器源,以查看使用默认值的频率.Sun ANSI C编译器前端有244个switch语句,每个语句平均有7个case.在所有这些案例中仅有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语义,这太糟糕了.
在很多方面,c只是标准装配惯用语的简洁接口.当编写跳转表驱动的流控制时,程序员可以选择通过或跳出"控制结构",跳出需要显式指令.
所以,c做同样的事情......
显然,要实现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); } }
如果案件被设计为隐含地破坏那么你就不会遭遇破坏.
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语句基本上会转到具有匹配值的标签.
这意味着中断是必要的,以避免传递到下一个标签下的代码.
至于原因为何有人以这种方式实现- 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;
允许这样的事情:
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
标签,它自然而然地变得更加自然.