0

重複の可能性:
「if、if、if」または「if、else if、else if、else」

1.

if(flag == 1)
{
    .....
}
else if(flag == 2)
{ 
     .....
}
else if(flag == 3) // true condition
{
     .....
}

または
2。

if(flag == 1)
{
    .....
}
if(flag == 2)
{ 
     .....
}
if(flag == 3) // true condition
{
     .....
}

最後に実行する場合if

4

6 に答える 6

6

私のテストでは、2 番目のバージョンは前のものよりも 4 命令短いですが、最適化されたバージョンは同じ長さであることが示されています。


私はコードをテストします:

main(a) {
  if(a == 10)
    puts("10");
  else if(a == 20)
    puts("20");
  else if(a < 100)
    puts("yes");
}

分解:

   0x00000000004004dc <+0>: push   rbp
   0x00000000004004dd <+1>: mov    rbp,rsp
   0x00000000004004e0 <+4>: sub    rsp,0x10
   0x00000000004004e4 <+8>: mov    DWORD PTR [rbp-0x4],edi
   0x00000000004004e7 <+11>:    cmp    DWORD PTR [rbp-0x4],0xa
   0x00000000004004eb <+15>:    jne    0x4004f9 <main+29>
   0x00000000004004ed <+17>:    mov    edi,0x4005c4
   0x00000000004004f2 <+22>:    call   0x4003b0 <puts@plt>
   0x00000000004004f7 <+27>:    jmp    0x40051b <main+63>
   0x00000000004004f9 <+29>:    cmp    DWORD PTR [rbp-0x4],0x14
   0x00000000004004fd <+33>:    jne    0x40050b <main+47>
   0x00000000004004ff <+35>:    mov    edi,0x4005c7
   0x0000000000400504 <+40>:    call   0x4003b0 <puts@plt>
   0x0000000000400509 <+45>:    jmp    0x40051b <main+63>
   0x000000000040050b <+47>:    cmp    DWORD PTR [rbp-0x4],0x63
   0x000000000040050f <+51>:    jg     0x40051b <main+63>
   0x0000000000400511 <+53>:    mov    edi,0x4005ca
   0x0000000000400516 <+58>:    call   0x4003b0 <puts@plt>
   0x000000000040051b <+63>:    leave  
   0x000000000040051c <+64>:    ret    

最適化:

   0x00000000004004dc <+0>: sub    rsp,0x8
   0x00000000004004e0 <+4>: cmp    edi,0xa
   0x00000000004004e3 <+7>: jne    0x4004f1 <main+21>
   0x00000000004004e5 <+9>: mov    edi,0x4005c4
   0x00000000004004ea <+14>:    call   0x4003b0 <puts@plt>
   0x00000000004004ef <+19>:    jmp    0x400511 <main+53>
   0x00000000004004f1 <+21>:    cmp    edi,0x14
   0x00000000004004f4 <+24>:    jne    0x400502 <main+38>
   0x00000000004004f6 <+26>:    mov    edi,0x4005c7
   0x00000000004004fb <+31>:    call   0x4003b0 <puts@plt>
   0x0000000000400500 <+36>:    jmp    0x400511 <main+53>
   0x0000000000400502 <+38>:    cmp    edi,0x63
   0x0000000000400505 <+41>:    jg     0x400511 <main+53>
   0x0000000000400507 <+43>:    mov    edi,0x4005ca
   0x000000000040050c <+48>:    call   0x4003b0 <puts@plt>
   0x0000000000400511 <+53>:    add    rsp,0x8
   0x0000000000400515 <+57>:    ret   

II テスト
コード:

main(a) {
  if(a == 10)
    puts("10");
  if(a == 20)
    puts("20");
  if(a < 100)
    puts("yes");
}

分解:

   0x00000000004004dc <+0>: push   rbp
   0x00000000004004dd <+1>: mov    rbp,rsp
   0x00000000004004e0 <+4>: sub    rsp,0x10
   0x00000000004004e4 <+8>: mov    DWORD PTR [rbp-0x4],edi
   0x00000000004004e7 <+11>:    cmp    DWORD PTR [rbp-0x4],0xa
   0x00000000004004eb <+15>:    jne    0x4004f7 <main+27>
   0x00000000004004ed <+17>:    mov    edi,0x4005c4
   0x00000000004004f2 <+22>:    call   0x4003b0 <puts@plt>
   0x00000000004004f7 <+27>:    cmp    DWORD PTR [rbp-0x4],0x14
   0x00000000004004fb <+31>:    jne    0x400507 <main+43>
   0x00000000004004fd <+33>:    mov    edi,0x4005c7
   0x0000000000400502 <+38>:    call   0x4003b0 <puts@plt>
   0x0000000000400507 <+43>:    cmp    DWORD PTR [rbp-0x4],0x63
   0x000000000040050b <+47>:    jg     0x400517 <main+59>
   0x000000000040050d <+49>:    mov    edi,0x4005ca
   0x0000000000400512 <+54>:    call   0x4003b0 <puts@plt>
   0x0000000000400517 <+59>:    leave  
   0x0000000000400518 <+60>:    ret

最適化:

   0x00000000004004dc <+0>: sub    rsp,0x8
   0x00000000004004e0 <+4>: cmp    edi,0xa
   0x00000000004004e3 <+7>: jne    0x4004f1 <main+21>
   0x00000000004004e5 <+9>: mov    edi,0x4005c4
   0x00000000004004ea <+14>:    call   0x4003b0 <puts@plt>
   0x00000000004004ef <+19>:    jmp    0x400507 <main+43>
   0x00000000004004f1 <+21>:    cmp    edi,0x14
   0x00000000004004f4 <+24>:    jne    0x400502 <main+38>
   0x00000000004004f6 <+26>:    mov    edi,0x4005c7
   0x00000000004004fb <+31>:    call   0x4003b0 <puts@plt>
   0x0000000000400500 <+36>:    jmp    0x400507 <main+43>
   0x0000000000400502 <+38>:    cmp    edi,0x63
   0x0000000000400505 <+41>:    jg     0x400511 <main+53>
   0x0000000000400507 <+43>:    mov    edi,0x4005ca
   0x000000000040050c <+48>:    call   0x4003b0 <puts@plt>
   0x0000000000400511 <+53>:    add    rsp,0x8
   0x0000000000400515 <+57>:    ret 

ブース テストは、Linux 3.2.14-1-ARCH x86_64 Intel(R) Core(TM) i5 CPU M 480 @ 2.67GHz 上の gcc バージョン 4.7.0 20120324 (プレリリース) (GCC) によってコンパイルされます。

編集: @Als が提案したように、基本的な最適化 ( -OGCC のフラグ) を含むバージョンを提供します。

于 2012-04-09T10:41:56.233 に答える
5

それらは論理的に同等ではありません。一致する条件が見つかると、Firstは他の条件
をチェックしません。 次に、以前の一致に関係なく、すべての条件をチェックします。 if
if

return2番目のケースでブロック内のステートメントを使用しているif場合、それらは論理的に同等になります。
ただし、確実にするために、環境でそれらをプロファイリングする必要があります。

于 2012-04-09T10:33:39.100 に答える
3

技術的には、提供された 2 つのコード スニペットは同等ではないため、それらを比較しても意味がありません。

2 番目のサンプルでは複数のifブロックが実行される可能性がありますが、最初のサンプルでは、​​ブロックを通るエグゼクティブのパスが 1 つしか保証されていません。したがって、この点で、平均して複数の条件が成功すると仮定すると、最初の条件の方が速く実行されると言えます。

ただし、1 つのパスのみが実行されると仮定すると、コンパイラがこのコードをアセンブリに変換する方法を知らなければ、確実に言うことはできなくなります。アセンブリには条件付きプリミティブがないためです (つまり、if-else)。

アセンブリ言語はCompareJump if less than zeroやなどの命令を使用Jump if zeroして条件付きロジックを実装します。関連する最適化を認識しないと、コンパイラはどちらがより高速に実行されるかを判断できない場合があります。

于 2012-04-09T10:35:27.597 に答える
0

@Hauletの投稿に追加するだけで、これは最適化でコンパイルしたときに得たものです。

jirka@debian:~/xpath/libxml-xpathengine-perl$ diff -Naur ./-.s o2.s 
--- ./-.s       2012-04-09 12:50:50.000000000 +0200
+++ o2.s        2012-04-09 12:52:25.000000000 +0200
@@ -22,43 +22,34 @@
        subl    $16, %esp
        movl    8(%ebp), %eax
        cmpl    $10, %eax
-       je      .L8
-       cmpl    $20, %eax
        je      .L9
+       cmpl    $20, %eax
+       je      .L10
        cmpl    $99, %eax
-       jle     .L10
+       jle     .L3
        leave
        .cfi_remember_state
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        .p2align 4,,4
        ret
-.L10:
-       .cfi_restore_state
-       movl    $.LC2, (%esp)
-       call    puts
-       leave
-       .cfi_remember_state
-       .cfi_restore 5
-       .cfi_def_cfa 4, 4
-       ret
-.L8:
+.L9:
        .cfi_restore_state
        movl    $.LC0, (%esp)
        call    puts
+.L3:
+       movl    $.LC2, (%esp)
+       call    puts
        leave
        .cfi_remember_state
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
-.L9:
+.L10:
        .cfi_restore_state
        movl    $.LC1, (%esp)
        call    puts
-       leave
-       .cfi_restore 5
-       .cfi_def_cfa 4, 4
-       ret
+       jmp     .L3
        .cfi_endproc
 .LFE0:
        .size   main, .-main

ご覧のとおり、ラベルのラベルは変更されていますが(L8 -> L9, L9 -> L10, L10 -> L3)、コードはほぼ同じです(機能の違いに必要な場合を除く)。

でコンパイルしました

gcc-4.7 -S -O3 -march=k8 -x c - 
于 2012-04-09T11:02:12.763 に答える
0

同時; 最初のif条件が真の場合、コードの最初のブロックは高速に実行されます。

于 2012-04-09T10:33:09.000 に答える
0

論理的には、コード スニペットは同等ではありませんね。たとえば、最初のものは言う

if (a==0)
{
}
else if (a < 10)
{
}
else if (a > 10)
{
}

二つ目は

if (a ==0)
{
}
if (a < 10)
{
}
if (a > 10)
{
}

上記は非常に些細な図です。ただし、ステートメントの実行時間を比較しようとしている場合if、それらが論理的に同等であると仮定すると、elseステートメントが実行されることはないため、最初のステートメントの方が高速になります。2 番目のケースでは、前のステートメントifに関係なく、条件が評価されます。if

于 2012-04-09T10:35:37.110 に答える