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

OB *_* OB 60 c c++ switch-statement conditional-statements

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

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

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

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

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

qrd*_*rdl 160

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

  1. 更清洁的代码.代码具有多个链接if/ else if ...看起来凌乱且难以维护 - switch提供更清晰的结构.

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

  3. 测试顺序无关紧要.为了加速一系列if/ else测试,需要首先考虑更多可能的案例.随着switch/ case程序员不需要考虑这个问题.

  4. 默认可以是任何地方.使用if/ elsedefault case必须在最后 - 最后else.In switch- default可以在任何地方,只要程序员发现它更合适.

  5. 常用代码.如果你需要为几种情况执行公共代码,你可能会省略break并且执行将"落空" - 这是你用if/ 无法实现的else.(/* FALLTHROUGH */对于这种情况,有一个很好的做法是对它进行特殊评论--Lint识别它并且没有抱怨,如果没有这个评论,它会抱怨,因为忘记是常见的错误break).

感谢所有评论者.

  • @Bill K:我刚用GCC测试它,即使用-O3,它也没有将if/else链优化成跳转表,而使用开关它甚至没有优化.其他编译器的里程可能会有所不同. (14认同)
  • 提及跳转表+1(密集值).或者二进制搜索,如果值是稀疏的.:-) (10认同)
  • @OB如果是if/else,您需要先放置更多可能的案例,以尽量减少执行的测试次数.如果是开关,您无需担心. (6认同)
  • +1 ,. 另外,顺序在switch中无关紧要,这在某些情况下很好,比如switch(x){default:assert(0 &&"dunno!"); 其他案例 - 这里}; (4认同)
  • 这将使一个真正混乱的编译器仍然是真的(可能是真的,但有人可能想要在用O4编译后检查程序集).我的猜测是,主要原因是人们仍然认为它表现更好. (3认同)
  • @Bill K:我不确定为什么你认为它需要一个混乱的编译器来进行至少80年代以来的优化.应该提到的是,大多数开关/外壳块都无法以这种方式进行优化,但有些可以.坚持使用switch/case的最大原因是它的语法非常清晰......遵循x路径之一,严格按变量Y的值确定. (2认同)

Eri*_* H. 31

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

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

switch (foo[bar][baz]) {
case 'a':
    ...
    break;
case 'b': 
    ...
    break;
}
Run Code Online (Sandbox Code Playgroud)

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

if (foo[bar][baz] == 'a') {
    ....
}
else if (foo[bar][baz+1] == 'b') {
    ....
}
Run Code Online (Sandbox Code Playgroud)

阅读你的代码的人会想知道"foo表达式应该是相同的",还是"为什么它们不同"?


dfa*_*dfa 16

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

  • 条件评估一次
  • 足够灵活,可以构建像Duff的设备
  • 通过(也称没有休息的情况)

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

  • 如果病情有副作用怎么办? (4认同)
  • 如果它不能作为switch语句完成,它可能只优化那些可以.通常情况下,编译器比程序员更加聪明. (2认同)

Jos*_*son 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)


Eri*_*lje 9

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

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


Hug*_*are 6

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

If (day == DAYOFWEEK_MONDAY) {
    //...
}
else if (day == DAYOFWEEK_TUESDAY) {
    //...
}
//etc...
Run Code Online (Sandbox Code Playgroud)

或者稍微容易阅读......

switch (day) {
    case DAYOFWEEK_MONDAY :
        //...
    case DAYOFWEEK_TUESDAY :
        //...
    //etc...
}
Run Code Online (Sandbox Code Playgroud)