【问题标题】:At what stage does an if/else become better than a switch case? Does it?if/else 在什么阶段变得比 switch case 更好?可以?
【发布时间】:2015-04-05 01:45:11
【问题描述】:

我可以总结一下,

  • Switch case 由实现定义,但主要定义为跳转表
  • 切换大小写使代码更具可读性
  • 切换速度比if/elseif (?) 快

考虑一个我有 300+ 个 switch 案例的案例。我知道这个场景中的if/elseif 会一团糟。

但我想知道switch 案例在 这样的场景?

  • 它是否可扩展,即无论存在多少情况,它仍然比 if/else 相对快?
  • 既然是执行 定义了我如何弄清楚我的编译器是如何实现它的?
  • 最重要的是,除了实际编写代码和使用分析器之外,我该如何进行if/elseif - switch 比较?我尝试使用gcc 4.8.1-S 开关编译一个带有switch case 的小型.c 文件,它看起来像是创建了一个跳转表。我从这里去哪里?
  • 在这种情况下使用if/elseif 是更好还是更差

我主要对 C/C++ 的具体细节感兴趣

【问题讨论】:

  • 无论如何,大多数现代编译器都会将一堆 if 优化到跳转表中,因此您不会注意到任何差异。也有人会争辩说,如果你必须在一个地方设置 300 个 if 条件,那么你的代码设计得很糟糕
  • @SingerOfTheFall 是的,我同意设计不当的部分。它是一个遗留代码,从它的用例来看,即运行时根据开关条件选择子类可能是最可行的
  • switch 的表现如何?测量它!是否可扩展?是的,最坏的情况就像 if/else 链。编译器如何实现开关?查看生成的汇编代码。它并不总是跳表。如果 case 标签中的值相距很远(例如 case 1、case 10000、case 90000),则 switch 将转换为 if/else 序列或 if/else 和跳转表的组合。 if/else 是否比 switch 更好?测量它。
  • 如果你有 300+ 个 switch case,你需要的是重构。
  • @Suvarna 向社区提出的更有趣的问题是如何修复这个设计不当的代码,这样您就不需要 switch 或 if/elseif 链。我期待看到这个问题:)

标签: c++ c performance switch-statement


【解决方案1】:

编译器可能决定使用跳转表并在 300+ 的情况下做出巨大改进。

编译器确实使用决策树等各种技术对分支进行优化。

编译器越容易理解代码越好。而且switch语句对于编译器来说也更具可读性。

从编译器的角度考虑 else if 。它看起来像一个箭头:

    - if 
     - else
      - else 
       - else
        - else

您需要评估每个之前的 if 才能得到正确的 else 。

但是 Switch 看起来更像一个块:

     - case
     - case
     - case
     - case

所以编译器有时可以直接确定去哪里。

对于您的项目符号问题:

  1. 它是可扩展的。开发者很容易编写,如果编译器使用跳转表添加更多的情况不会影响。

  2. 由编译器决定使用什么。它可能会选择根本不优化它(但很可能是跳转表)。

  3. 您可以运行一个循环并手动测量时间吗?

  4. 使用 switch 总是更好。在最坏的情况下,开关将充当 if/else。

【讨论】:

  • 第 4 点。-> 有道理。谢谢
  • "使用 switch 总是更好。"在性能方面,是的。在可读性和程序员错误的可能性方面,没有。
  • 为什么编译器不能确定给定的 if..else 语句集在逻辑上等同于 switch,并进行相应的优化?
  • @PaulDraper:即使在性能方面,如果每个 if 最终在大约一半的执行时间中为真(所以一半的项目满足第一个if,四分之一满足第二个,一个满足第三个,等等。显然,指数衰减不会持续到300个项目,而是使用if声明列表中代表最常见用例的部分与switch 相比,有时可能是一个重大胜利。
  • @PythonNut,sufficiently smart compiler 当然可以。最可能的原因是程序员无意中以编译器无法转换的方式编写了 if-else。从一开始就编写一个 switch-case 可以保证这一点。仅供参考,其他语言的一些功能试图弥合抽象/优化差距。 Scala有@switch注解,需要编译到JVM tableswitch或者lookupswitch,否则编译失败。
【解决方案2】:

大多数低端处理器的编译器(主要用于嵌入式系统)编译器并不总是为 switch case 生成跳转表。

如果 case 变量是按顺序排列的(例如 1,2,3,4....),那么编译器会首选 switch case 的跳转表实现,但是对于 case 变量的随机序列(例如 12,344,565,1,5 ...) 编译器生成与 if-else 代码相同的代码。

有时,由于这种情况,开发人员在向已经正常的代码中添加随机案例变量时会遇到麻烦,这可能会改变该部分代码的整个实现,从而导致代码执行时间和代码大小发生重大变化。这些是嵌入式开发人员最关心的一点。

【讨论】:

  • @EJP 为什么这是不真实的?我在我的一个项目中遇到过这个问题。我并不是说这是所有编译器的行为。如果遗漏了什么,请解释我的观点。
  • 我的观点是,当您在资源关键型系统中使用 switch 语句时,您应该知道您的编译器正在处理您的代码。
  • 你应该说“如果…编译器生成…”如果你的意思是“如果…编译器可能生成…”或“我遇到一个编译器这会产生……如果……”
  • @Holger,您是否考虑过使用 switch 重写您的评论? ;)
  • 该死的错字应该是:你不应该说“如果…编译器生成…”如果你的意思是“如果…编译器可能生成...”或“我遇到了一个编译器生成 ...if ...”
【解决方案3】:

从将 switch 与 if..then..else 构造进行比较的问题来看,~我假设您只关心需要单个测试并且结果取决于答案的情况(例如,如果 x = = ?? 然后...)。 在这种情况下,最好使用开关,因为: a)您不能在测试链的中途引入错误条件。 b) 测试只进行一次。

【讨论】:

    【解决方案4】:

    如果您没有多少选择、具有深度决策树或需要使用非特定决策,则 if else 比 switch case 更好,

    即。很容易实现一个检查 int 是否大于 0 的 if 语句,这在 switch 语句中更难构建。这是最好使用 if 语句实现的逻辑类型。

    如果您有一个扁平的、非常宽泛但依赖于特定条件的决策表,那么 switch 案例会更好。例如,如果值是 1、2、3、4...等到 10,您希望发生特定的事情,使用 switch case 会更容易和更明智。

    最终,现代编译器会将其更改为计算效率最高的任何内容,但构建它的方式会影响构建后的功能和可支持性。

    【讨论】:

      猜你喜欢
      • 2012-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 2011-11-09
      相关资源
      最近更新 更多