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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1028437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:27:55  来源:igfitidea点击:

Why Switch/Case and not If/Else If?

c++cswitch-statementconditional-statements

提问by OB OB

This question in mainly pointed at C/C++, but I guess other languages are relevant as well.

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

I can't understand why is switch/case still being used instead of if/else if. It seems to me much like using goto's, and results in the same sort of messy code, while the same results could be acheived with if/else if's in a much more organized manner.

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

Still, I see these blocks around quite often. A common place to find them is near a message-loop (WndProc...), whereas these are among the places when they raise the heaviest havoc: variables are shared along the entire block, even when not propriate (and can't be initialized inside it). Extra attention has to be put on not dropping break's, and so on...

尽管如此,我还是经常看到这些街区。找到它们的常见位置是靠近消息循环 (WndProc...),而这些是它们引发最严重破坏的地方:变量在整个块中共享,即使不合适(并且不能在其中初始化)。必须特别注意不要放弃休息,等等......

Personally, I avoid using them, and I wonder wether I'm missing something?

就个人而言,我避免使用它们,我想知道我是否遗漏了什么?

Are they more efficient than if/else's? Are they carried on by tradition?

它们比 if/else 更有效率吗?他们是按照传统进行的吗?

回答by qrdl

Summarising my initial post and comments - there are several advantages of switchstatement over if/elsestatement:

总结我最初的帖子和评论 -switch声明比if/else声明有几个优点:

  1. Cleaner code. Code with multiple chained if/else if ...looks messy and is difficult to maintain - switchgives cleaner structure.

  2. Performance. For dense casevalues compiler generates jump table, for sparse - binary search or series of if/else, so in worst case switchis as fast as if/else, but typically faster. Although some compilers can similarly optimise if/else.

  3. Test order doesn't matter. To speed up series of if/elsetests one needs to put more likely cases first. With switch/caseprogrammer doesn't need to think about this.

  4. Default can be anywhere. With if/elsedefault case must be at the very end - after last else. In switch- defaultcan be anywhere, wherever programmer finds it more appropriate.

  5. Common code. If you need to execute common code for several cases, you may omit breakand the execution will "fall through" - something you cannot achieve with if/else. (There is a good practice to place a special comment /* FALLTHROUGH */for such cases - lint recognises it and doesn't complain, without this comment it does complain as it is common error to forgot break).

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

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

  3. 测试顺序无关紧要。为了加快一系列if/else测试,需要将更多可能的案例放在第一位。用switch/case程序员不需要考虑这个。

  4. 默认可以在任何地方。with if/ elsedefault case 必须在最后 - 在 last 之后else。In switch-default可以在任何地方,任何程序员认为更合适的地方。

  5. 通用代码。如果您需要为多种情况执行通用代码,您可以省略break并且执行将“失败” - 这是您无法使用if/实现的else。(/* FALLTHROUGH */对于这种情况,有一个很好的做法是放置特殊注释- lint 会识别它并且不会抱怨,没有此注释它会抱怨,因为忘记是常见的错误break)。

Thanks to all commenters.

感谢所有评论者。

回答by Eric H.

Well, one reason is clarity....

嗯,原因之一是清晰度....

if you have a switch/case, then the expression can't change.... i.e.

如果你有一个 switch/case,那么表达式就不能改变......即

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

whereas with if/else, if you write by mistake (or intent):

而使用 if/else,如果你写错了(或有意):

if (foo[bar][baz] == 'a') {
    ....
}
else if (foo[bar][baz+1] == 'b') {
    ....
}

people reading your code will wonder "were the foo expressions supposed to be the same", or "why are they different"?

阅读您代码的人会想知道“foo 表达式是否应该相同”,或者“它们为什么不同”?

回答by dfa

please remember that case/select provides additional flexibility:

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

  • condition is evaluated once
  • is flexible enough to build things like the Duff's device
  • fallthrough (aka case without break)
  • 条件被评估一次
  • 足够灵活,可以构建像Duff 的设备这样的东西
  • fallthrough(又名案件没有中断)

as well as it executes much faster(via jump/lookup table) * historically

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

回答by Joseph Paterson

Also remember that switch statements allows the flow of control to continue, which allows you to nicely combine conditions while allowing you to add additional code for certain conditions, such as in the following piece of code:

还要记住 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;
}

Using if/elsestatements here instead would not be anywhere as nice.

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;
}

回答by Eric Petroelje

If there are lots of cases, the switch statement seems cleaner.

如果有很多情况,switch 语句看起来更简洁。

It's also nice when you have multiple values for which you want the same behavior - just using multiple "case" statements that fall through to a single implementation is much easier to read than a if( this || that || someotherthing || ... )

当您有多个想要相同行为的值时,这也很好 - 仅使用多个“case”语句来实现单个实现比 if( this || that || someotherthing || .. .)

回答by Hugoware

It might also depend on your language -- For example, some languages switch only works with numeric types, so it saves you some typing when you're working with an enumerated value, numeric constants... etc...

这也可能取决于您的语言——例如,某些语言开关仅适用于数字类型,因此当您使用枚举值、数字常量...等时,它可以为您节省一些输入。

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

Or slightly easier to read...

或者更容易阅读...

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

回答by Randolpho

Switch/case is usually optimized more efficiently than if/else if/else, but is occasionally (depending on language and compiler) translated to simple if/else if/else statements.

switch/case 通常比 if/else if/else 优化更有效,但偶尔(取决于语言和编译器)被翻译成简单的 if/else if/else 语句。

I personally think switch statements makes code more readable than a bunch of if statements; provided that you follow a few simple rules. Rules you should probably follow even for your if/else if/else situations, but that's again my opinion.

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

Those rules:

这些规则:

  • Never, ever, have more than one line on your switch block. Call a method or function and do your work there.
  • Always check for break/ case fallthrough.
  • Bubble up exceptions.
  • 永远不要在您的开关块上有多于一行。调用一个方法或函数并在那里完成你的工作。
  • 始终检查中断/案例失败。
  • 冒泡异常。

回答by Carl Manaster

Clarity. As I said here, a clue that else ifis problematic is

明晰。正如我在这里所说的,一个else if有问题的线索是

the frequency with which ELSE IF is used in a far more constrained way than is allowed by the syntax. It is a sledgehammer of flexibility, permitting entirely unrelated conditions to be tested. But it is routinely used to swat the flies of CASE, comparing the same expression with alternate values...

This reduces the readability of the code. Since the structure permits a universe of conditional complexity, the reader needs to keep more possibilities in mind when parsing ELSE IF than when parsing CASE.

ELSE IF 的使用频率比语法允许的要严格得多。这是一个灵活的大锤,允许测试完全不相关的条件。但它通常用于打击 CASE 的苍蝇,将相同的表达式与替代值进行比较......

这降低了代码的可读性。由于该结构允许条件复杂性的范围,读者在解析 ELSE IF 时需要记住比解析 CASE 时更多的可能性。

回答by Bill K

Actually a switch statement implies that you are working off of something that is more or less an enum which gives you an instant clue what's going on.

实际上,一个 switch 语句意味着您正在处理或多或少是一个枚举的东西,它可以让您立即了解正在发生的事情。

That said, a switch on an enum in any OO language could probably be coded better--and a series of if/else's on the same "enum" style value would be at least as bad and even worse at conveying meaning.

也就是说,在任何 OO 语言中切换枚举可能会更好地编码 - 并且在相同“枚举”样式值上的一系列 if/else 在传达含义方面至少同样糟糕,甚至更糟。

回答by JustJeff

addressing the concern that everything inside the switch has equivalent scope, you can always throw your case logic into another { } block, like so ..

解决 switch 内的所有内容都具有等效作用域的问题,您始终可以将案例逻辑扔到另一个 { } 块中,就像这样..

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

.. now I'm not saying that's pretty. Just putting it out there as something that's possibleif you absolutely have to isolate something in one case from another.

..现在我不是说那很漂亮。如果您绝对必须将一种情况下的某些东西与另一种情况隔离开来,就将其作为可能的东西放在那里。

one other thought on the scope issue - it seems like a good practice to only put one switch inside a function, and not a lot else. Under those circumstances, variable scope isn't as much of a concern, since that way you're generally only dealing with one case of execution on any given invocation of the function.

关于作用域问题的另一种想法 - 在函数中只放置一个开关,而不是其他很多,这似乎是一种很好的做法。在这些情况下,变量作用域不是那么重要,因为这样您通常只处理对函数的任何给定调用的一种执行情况。

ok, one last thought on switches: if a function contains more than a couple of switches, it's probably time to refactor your code. If a function contains nestedswitches, it's probably a clue to rethink your design a bit =)

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