为什么Switch / Case而不是If / Else If?

时间:2009-06-22 17:26:19

标签: c++ c switch-statement conditional-statements

这个问题主要针对C / C ++,但我猜其他语言也是相关的。

我无法理解为什么仍然使用switch / case而不是if / else if。在我看来,很像使用goto,并导致相同类型的混乱代码,而if / else如果以更有条理的方式可以实现相同的结果。

不过,我经常看到这些街区。找到它们的一个常见位置是在消息循环(WndProc ...)附近,而这些是它们引发最严重破坏的地方之一:变量在整个块中共享,即使不是主要的(也不是在里面初始化)。必须特别注意不要放弃休息,等等......

就个人而言,我避免使用它们,我想知道我错过了什么?

它们比if / else更有效吗? 它们是按照传统继承的吗?

15 个答案:

答案 0 :(得分:159)

总结我的初始帖子和评论 - switch语句优于if / else语句有以下几个优点:

  1. 清洁代码。具有多个链式if / else if ...的代码看起来很混乱,难以维护 - switch使结构更清晰。

  2. 性能。对于密集case值,编译器生成跳转表,用于稀疏 - 二进制搜索或一系列if / else,因此在最坏的情况下switchif一样快} / else,但通常更快。虽然某些编译器可以类似地优化if / else

  3. 测试顺序无关紧要。为了加快一系列if / else测试,需要首先考虑更多可能的案例。使用switch / case程序员无需考虑这一点。

  4. 默认可以在任何地方。 if / else默认情况必须在最后else之后。 switch - default可以在任何地方,只要程序员发现它更合适。

  5. 常用代码。如果您需要针对多种情况执行公共代码,则可能会忽略break并且执行将“失败” - 这是if / else无法实现的。 (对于这种情况,有一个特殊的评论/* FALLTHROUGH */是一种很好的做法--Lint识别它并且没有抱怨,如果没有这个评论,它会抱怨,因为忘记break)是常见的错误。 / p>

  6. 感谢所有评论者。

答案 1 :(得分:31)

嗯,一个原因是清晰......

如果你有一个开关/案例,那么表达式不能改变.... 即。

switch (foo[bar][baz]) {
case 'a':
    ...
    break;
case 'b': 
    ...
    break;
}

而if if / else,如果你错误地写(或意图):

if (foo[bar][baz] == 'a') {
    ....
}
else if (foo[bar][baz+1] == 'b') {
    ....
}
阅读你的代码的人会怀疑“foo表达式应该是相同的”,还是“为什么它们不同”?

答案 2 :(得分:16)

请记住,case / select提供了额外的灵活性:

  • 条件评估一次
  • 足够灵活,可以构建Duff's device
  • 之类的内容
  • fallthrough(又名没有休息的情况)

以及执行得更快(通过跳转/查找表)*历史性

答案 3 :(得分:11)

还要记住,switch语句允许控制流继续,这允许您很好地组合条件,同时允许您为特定条件添加其他代码,例如在下面的代码中:

switch (dayOfWeek)
{
    case MONDAY:
        garfieldUnhappy = true;
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
       weekDay = true;
       break;
    case SATURDAY:
       weekendJustStarted = true;
    case SUNDAY:
       weekendDay = true;
       break;
}

在这里使用if/else语句不会有任何好处。

if (dayOfWeek == MONDAY)
{
    garfieldUnhappy = true;
}
if (dayOfWeek == SATURDAY)
{
    weekendJustStarted = true;
}
if (dayOfWeek == MONDAY || dayOfWeek == TUESDAY || dayOfWeek == WEDNESDAY
    || dayOfWeek == THURSDAY || dayOfWeek == FRIDAY)
{
    weekDay = true;
}
else if (dayOfWeek == SATURDAY || dayOfWeek == SUNDAY)
{
    weekendDay = true;
}

答案 4 :(得分:9)

如果有很多情况,那么switch语句似乎更清晰。

当你有多个你想要相同行为的值时,这也很好 - 只使用多个“case”语句,这些语句落到单个实现中比if(这个||那个|| someotherthing |)更容易阅读。 | ...)

答案 5 :(得分:6)

它可能还取决于您的语言 - 例如,某些语言切换仅适用于数字类型,因此当您使用枚举值,数字常量等等时,它可以节省一些输入... < / p>

If (day == DAYOFWEEK_MONDAY) {
    //...
}
else if (day == DAYOFWEEK_TUESDAY) {
    //...
}
//etc...

或者稍微容易阅读...

switch (day) {
    case DAYOFWEEK_MONDAY :
        //...
    case DAYOFWEEK_TUESDAY :
        //...
    //etc...
}

答案 6 :(得分:4)

开关/案例通常比if / else if / else更有效地进行优化,但偶尔(取决于语言和编译器)转换为简单的if / else if / else语句。

我个人认为switch语句使代码比一堆if语句更具可读性;只要遵循一些简单的规则即可。您甚至应该遵循if / else if / else情况的规则,但这也是我的意见。

这些规则:

  • 切换块上永远不会有多行。调用方法或函数并在那里完成工作。
  • 请务必检查休息/案例漏洞。
  • 冒充异常。

答案 7 :(得分:4)

净度。正如我所说hereelse if有问题的线索是

  

ELSE IF的频率   以更加有限的方式使用   比语法所允许的。它是一个   灵活的大锤,   允许完全无关   要测试的条件。但它是   经常用来拍打苍蝇   CASE,比较相同的表达式   具有替代值......

     

这降低了可读性   码。由于结构允许   条件复杂性的宇宙,   读者需要保持更多   解析时的可能性   ELSE IF比解析CASE时。

答案 8 :(得分:4)

实际上,一个转换语句意味着你正在处理一个或多或少是枚举的东西,它会让你立即知道发生了什么。

也就是说,任何OO语言中枚举的开关都可以更好地编码 - 并且在相同的“枚举”样式值上的一系列if / else将至少同样糟糕,甚至更难以传达意义。

答案 9 :(得分:3)

解决了交换机内部所有内容都具有相同范围的问题,您可以随时将您的案例逻辑抛入另一个{}块,如此...

switch( thing ) {
    case ONETHING: {
        int x; // local to the case!
        ...
        }
        break;
    case ANOTHERTHING: {
        int x; // a different x than the other one
        }
        break;
}

..现在我不是说这很漂亮。如果您绝对不得不在一个案例中将某些案件与另一个案件隔离开来,那就把它作为可能的东西放在那里。

关于范围问题的另一个想法 - 将一个开关放在一个函数中而不是其他很多东西似乎是一个好习惯。在这种情况下,变量范围并不是一个值得关注的问题,因为通常情况下,您通常只处理任何给定函数调用的一个执行情况。

好的,关于开关的最后一个想法:如果一个函数包含多个开关,那么可能是重构代码的时候了。如果一个函数包含嵌套开关,它可能是一个重新思考你的设计的线索=)

答案 10 :(得分:1)

switch case主要用于在编程中做出选择。这与条件语句无关:

如果您的程序只需要选择,那么为什么使用if / else块并增加编程工作量,这会降低程序的执行速度。

答案 11 :(得分:0)

非常确定他们编译的内容与if / else if相同,但当超过2或3时,我发现switch / case更容易阅读else秒。

答案 12 :(得分:0)

可以针对速度优化Switch语句,但是如果案例值分布在大量值上,则可以占用更多内存。

if / else通常很慢,因为需要检查每个值。

答案 13 :(得分:0)

Smalltalker可能会拒绝switch和if-then-else,并且可能会写出如下内容: -

shortToLongDaysMap := Dictionary new.

shortToLongDaysMap
at: 'Mon'     put:  'Monday';
at: 'Tue'     put:  'Tuesday';
at: 'Wed'     put:  'Wednesday'
etc etc.

longForm := shortToLongDaysMap at: shortForm ifAbsent: [shortForm]

这是一个简单的例子,但我希望你能看到这种技术如何适用于大量案例。

注意at:IfAbsent:的第二个参数类似于case语句的default子句。

答案 14 :(得分:0)

这背后的主要原因是可维护性和可读性。使用Switch / case语句然后if / else很容易使代码更易读和可维护。因为你有很多if / else然后代码变得像nest一样混乱,很难维护它。

还有一些执行时间是另一个原因。