“if if”与“if else if”的性能差异

时间:2011-11-01 17:22:59

标签: c++ c

我只是在想C / C ++中的两个语句之间是否有任何性能差异:

案例1:

if (p==0)
   do_this();
else if (p==1)
   do_that();
else if (p==2)
   do_these():

案例2:

if(p==0)
    do_this();
if(p==1)
    do_that();
if(p==2)
    do_these();

7 个答案:

答案 0 :(得分:34)

假设简单类型(在这种情况下,我使用int)并且没有有趣的业务(没有重新定义operator = for int),至少在AMD64上使用GCC 4.6,没有区别。生成的代码完全相同:

0000000000000000 <case_1>:                                   0000000000000040 <case_2>:
   0:   85 ff                   test   %edi,%edi               40:   85 ff                   test   %edi,%edi
   2:   74 14                   je     18 <case_1+0x18>        42:   74 14                   je     58 <case_2+0x18>
   4:   83 ff 01                cmp    $0x1,%edi               44:   83 ff 01                cmp    $0x1,%edi
   7:   74 27                   je     30 <case_1+0x30>        47:   74 27                   je     70 <case_2+0x30>
   9:   83 ff 02                cmp    $0x2,%edi               49:   83 ff 02                cmp    $0x2,%edi
   c:   74 12                   je     20 <case_1+0x20>        4c:   74 12                   je     60 <case_2+0x20>
   e:   66 90                   xchg   %ax,%ax                 4e:   66 90                   xchg   %ax,%ax
  10:   f3 c3                   repz retq                      50:   f3 c3                   repz retq 
  12:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)        52:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
  18:   31 c0                   xor    %eax,%eax               58:   31 c0                   xor    %eax,%eax
  1a:   e9 00 00 00 00          jmpq   1f <case_1+0x1f>        5a:   e9 00 00 00 00          jmpq   5f <case_2+0x1f>
  1f:   90                      nop                            5f:   90                      nop
  20:   31 c0                   xor    %eax,%eax               60:   31 c0                   xor    %eax,%eax
  22:   e9 00 00 00 00          jmpq   27 <case_1+0x27>        62:   e9 00 00 00 00          jmpq   67 <case_2+0x27>
  27:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)        67:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
  2e:   00 00                                                  6e:   00 00 
  30:   31 c0                   xor    %eax,%eax               70:   31 c0                   xor    %eax,%eax
  32:   e9 00 00 00 00          jmpq   37 <case_1+0x37>        72:   e9 00 00 00 00          jmpq   77 <case_2+0x37>
  37:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
  3e:   00 00 

case_1末尾的额外指令仅适用于padding (to get the next function aligned)

这并不奇怪,因为该函数中的p没有改变是相当基本的优化。如果p可以改变(例如,通过引用传递或指向各种do_…函数,或者是引用或指针本身,所以可能存在别名)那么行为就不同了,当然生成的代码也是。

答案 1 :(得分:21)

在前一种情况下,匹配的匹配后的条件不会被评估。

答案 2 :(得分:11)

if else 更快;如果在最后一个之前找到匹配,那么至少跳过最后一个if语句,如果首先找到匹配,它将跳过所有其他语句。

如果 更慢;即使使用第一个if语句找到匹配项,它也将继续尝试匹配其他语句。

答案 3 :(得分:7)

是的,性能差异是:

第二个陈述评估每个IF

答案 4 :(得分:3)

对于如此有限数量的表达式,您可能不会注意到性能的任何差异。但理论上,if..if..if需要检查每个表达式。如果单个表达式是互斥的,则可以使用if..else if..来保存该评估。这种方式只有在前面的情况失败时才会检查另一个表达式。

请注意,只检查int是否相等,您也可以使用switch语句。这样,您仍然可以保持一定程度的可读性,以进行长时间的检查。

switch ( p )
{
    case 0:
        do_this();
        break;

    case 1:
        do_that();
        break;

    case 2:
        do_these():
        break;
}

答案 5 :(得分:2)

正如已经证明的那样......它有所不同。

如果我们讨论像int这样的原始(内置)类型,那么编译器可能足够智能,因此无关紧要(或不重要)。但在任何情况下,性能影响都会很小,因为调用函数的成本远高于if的成本,因此如果您尝试测量它,差异可能会在噪声中丢失。 / p>

然而,语义却截然不同。

当我读到第一个案例时:

if (...) {
  // Branch 1
} else if (...) {
  // Branch 2
}

然后我知道无论两个分支可能做什么,只能执行一个。

然而,当我读到第二个案例时:

if (...) {
}
if (...) {
}

然后我不得不怀疑是否有可能两个分支被采用,这意味着我必须仔细检查第一个代码以确定它是否可能影响第二个测试。当我最终得出结论并非如此时,我诅咒这个血淋淋的开发人员,他懒得写那该死的else,这会让我在最后10分钟的审查中得救。

因此,帮助自己和未来的维护者,并专注于使语义正确和清晰。

在这个问题上,人们可能会争辩说,这个调度逻辑可能更好地用其他结构表达,例如switch或者map<int, void()>? (注意后者并避免过度工程;))

答案 6 :(得分:0)

主要区别在于if / else构造将在其中一个返回true后停止评估ifs()。这意味着它可能只在执行bailing之前执行1或2个ifs。另一个版本将检查所有3个ifs,无论其他的结果如何。

所以....如果/ else的运营成本为“最多3次检查”。 if / if / if版本的运营成本为“始终进行3次检查”。假设检查所有3个值的可能性相同,if / else版本将执行平均1.5 ifs,而if / if版本将始终执行3 ifs。从长远来看,使用“else”结构可以节省1.5%的CPU时间。