【问题标题】:In C, which is faster: if with returns, or else if with returns?在 C 中,哪个更快:如果有返回,或者如果有返回?
【发布时间】:2010-11-13 14:45:14
【问题描述】:

如果 if 语句中的每个块都返回,是 if / else if 更好,还是有 if 链更好?具体来说,如果最快的话:

答:

if (condition1) {
  code1;
  return a;
}
if (condition2) {
  code2;
  return b;
}
//etc...

乙:

if (condition1) {
  code1;
  return a;
}
else if (condition2) {
  code2;
  return b;
}
//etc...

【问题讨论】:

  • 我会 assume 前者更快,但使用第二个可能会更好,因为更清楚的是,除非第一个 if 块不会被执行,否则第二个 if 块将不会被执行条件失败。
  • 不,C 没有规定在 CPU 级别会发生什么。似乎有一个没有 JMP 语句的 CPU 架构,它使用一个标志来执行语句但丢弃结果。这意味着速度是相同的。我的观点:你不能假设 C 代码会在幕后变成什么样子。
  • “架构......它使用一个标志仍然执行语句但丢弃结果”。例如 ARM 有条件指令,如果条件标志被设置,则执行,如果没有,则作为 nops。它们是由编译器在跳转比它要跳过的操作数慢的情况下发出的。
  • 在“else if (statement)”中执行语句并丢弃结果将意味着编译器严重损坏。
  • 我假设这种情况下的“结果”是指“包括任何副作用”。也就是说,汇编指令的结果,而不是表达式计算结果在 C 意义上的结果。显然,如果“code1”和“code2”不是完全内联的,那么编译器就不能使用这个选项。

标签: c optimization performance conditional


【解决方案1】:

没有区别,这是微优化的不必要尝试。

【讨论】:

  • +1 任何体面的编译器都会注意到 else 是不需要的。
  • 这甚至不是微优化。这是一个 0 优化。
  • 你不能总是假设编译器是健全的。通常当人们询问速度时,他们使用的是带有糟糕编译器的嵌入式系统。它不止一次发生在我身上。世界比 x86 和 ARM 系列更大。当然,嵌入式程序员可以只编译两者并查看生成的操作码并进行计时。
  • @Nosredna:是的,但是如果我们假设编译器是疯狂的,那么如果没有看到 OP 正在使用的确切编译器的输出,我们就什么也说不出来。未能指定您在 OP 中使用的确切架构/编译器意味着您可以接受涵盖理论/逻辑/正常/正常情况的答案。
  • 即使使用非常基本的非优化编译器,也不会有任何速度差异。 “else”不是一个需要时间的陈述。它只是指示当条件不满足时跳转到哪里。一个非常原始的编译器可能会在 if 块的末尾,就在第一个 return 语句之后添加一个无用的 jmp 语句(跳转到 else 块之后的第一条语句)。
【解决方案2】:

这应该在优化的构建中执行相同的操作。如果不是,那么其他原因可能会阻止编译器做“正确的事情”。

机器人不正确。在这两种情况下,如果第一个子句为真,则不会执行(评估)后续语句。

注意,一定要衡量——你可能优化了错误的东西。

【讨论】:

    【解决方案3】:

    C 标准规定了基于 C 代码创建的机器语言。如果您了解底层架构,您有时可以做出假设,但即使这样也是不明智的。

    CPU 只是简单的野兽的日子早已过去,现在它们具有流水线、多级缓存和各种其他奇妙的东西来将它们的速度推向极限。

    在遇到特定问题之前,您不应该担心这种优化级别(有些人会说“完全”)。

    编写可读的代码

    这应该是规则 1、2 和 3。您认为哪个是软件开发中最大的问题,代码以最高速度的 99.5% 运行,或者开发人员花费数天时间试图找出和/或修复同事的问题(甚至他们自己)六个月前做过?

    我的建议是,仅当您发现性能存在问题时才考虑性能,然后在目标平台上进行基准测试,看看哪里可以获得最大的改进。 if 语句中 1% 的改进可能会因在代码的其他地方选择更好的算法而相形见绌(当然,其他事情,例如代码被调用的次数是相等的)。优化应始终以实现最佳性价比为目标。

    【讨论】:

    • ++ 有时,如果我在做图形或其他事情,并且某些例程是一个实际的热点并且会从循环压缩中受益,我可能会关心。另外 99.99% 的情况下,性能问题是由对函数的过度调用引起的,这些函数的作用远超出编码人员的预期。
    【解决方案4】:

    有了这些回报,else 是多余的。编译器可能足够聪明,可以解决这个问题。

    我怀疑编译器会为两者生成相同的代码。拆开看看。

    无论如何,检查编译器的输出和经验性能测试是唯一确定的方法。

    【讨论】:

      【解决方案5】:

      它们在大多数架构上应该是等效的。生成的指令可能仍然是相同的 bne、cmps 和 rets。

      如果您使用 switch/case 而不是 if 语句,可能会有所帮助。

      【讨论】:

        【解决方案6】:

        如果有的话,我真的不认为有很大的不同:

        对于 A 案例:

        if (condition){
            //conditionOp
            //cmp ... , ...
            //jxx :toEndIf
            code;
            return bar;
            //mov eax, bar
            //jmp :toEnd
        }
        if(condition){
            //conditionOp
            //cmp ... , ...
            //jxx :toEndIf
            code;
            return bar;
            //mov eax, bar
            //jmp :toEnd
        }
        

        对于 B 情况:

        if(condition){
            //conditionOp
            //cmp ... , ...
            //jxx :toElse + 1
            code;
            return bar;
            //mov eax , bar
            //jmp :toEnd
        } else 
            //jmp :endElse 
        if (condition2){
            //conditionOp
            //cmp ... , ...
            //jxx :endElse
            code;
            return bar;
            //mov eax, bar
            //jmp :toEnd
        }
        

        因此,使用 B 情况,添加了一条额外的指令。不过,针对大小进行优化可能会消除这种情况。

        【讨论】:

        • +1 表示额外码数,但您可能需要说明它适用于特定的 CPU/编译器/优化级别/月相。
        • 例如,GCC 不会为 x86 发出这样的代码,即使没有任何优化。
        【解决方案7】:

        编写一个简单的测试程序来测量并找出答案 - 但是这是不必要的优化。

        【讨论】:

          猜你喜欢
          • 2013-04-28
          • 2016-06-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-15
          • 2020-07-28
          相关资源
          最近更新 更多