2014-01-12 13 views
-3

之间是否有区别,如果同时突破

if(x){ 

    //stuff 
} 

while(x){ 

    //stuff 
    break; 
} 

之间的差异?

其中一个更快?

+1

获取有关C++的入门书! – Nawaz

+0

@Nawaz我想你无法在介绍性书籍 – Vider7CC

+2

中发现我怀疑有人生气。如果你确实对此感兴趣,那么实际测量它并检查你自己是否真的没有想到这一点是令人惊讶的。或者阅读更多关于C++的内容。 – BartoszKP

回答

4

让我们找到它了:

void Test1() { 
    while (GetTickCount()) { 
     printf("Hello World Test1"); 
     break; 
    } 
} 

void Test2() { 
    if (GetTickCount()) { 
     printf("Hello World Test2"); 
    } 
} 

void main() { 
    Test1(); Test2(); 
} 

编译使用VC 2013年11月CTP的释放与全面优化:

CPU Disasm 
Address Hex dump   Command         Comments 
012A12A0 /$ FF15 00302A01 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
012A12A6 |. 85C0   TEST EAX,EAX 
012A12A8 |. 74 0E   JZ SHORT 012A12B8 
012A12AA |. 68 8C312A01 PUSH OFFSET 012A318C      ; ASCII "Hello World Test1" 
012A12AF |. FF15 64302A01 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
012A12B5 |. 83C4 04  ADD ESP,4 
012A12B8 |> FF15 00302A01 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
012A12BE |. 85C0   TEST EAX,EAX 
012A12C0 |. 74 0E   JZ SHORT 012A12D0 
012A12C2 |. 68 A0312A01 PUSH OFFSET 012A31A0      ; ASCII "Hello World Test2" 
012A12C7 |. FF15 64302A01 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
012A12CD |. 83C4 04  ADD ESP,4 
012A12D0 |> 33C0   XOR EAX,EAX 
012A12D2 \. C3   RETN 

正如你可以看到相同的代码由VC编译器生成。这虽然不是这种情况,如果禁止优化:

Test1的

CPU Disasm 
Address Hex dump   Command         Comments 
00F91630 /$ 55   PUSH EBP         ; Playground.Test1(void) 
00F91631 |. 8BEC   MOV EBP,ESP 
00F91633 |> FF15 0030F900 /CALL DWORD PTR DS:[<&KERNEL32.GetTickCo ; [KERNEL32.GetTickCount 
00F91639 |. 85C0   |TEST EAX,EAX 
00F9163B |. 74 12   |JZ SHORT 00F9164F 
00F9163D |. 68 9C31F900 |PUSH OFFSET 00F9319C     ; ASCII "Hello World Test1" 
00F91642 |. FF15 6430F900 |CALL DWORD PTR DS:[<&MSVCR120.printf>] 
00F91648 |. 83C4 04  |ADD ESP,4 
00F9164B |. EB 02   |JMP SHORT 00F9164F 
00F9164D |.^ EB E4   \JMP SHORT 00F91633 
00F9164F |> 5D   POP EBP 
00F91650 \. C3   RETN 

的Test2

CPU Disasm 
Address Hex dump   Command         Comments 
00F91660 /$ 55   PUSH EBP         ; Playground.Test2(void) 
00F91661 |. 8BEC   MOV EBP,ESP 
00F91663 |. FF15 0030F900 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
00F91669 |. 85C0   TEST EAX,EAX 
00F9166B |. 74 0E   JZ SHORT 00F9167B 
00F9166D |. 68 B031F900 PUSH OFFSET 00F931B0      ; ASCII "Hello World Test2" 
00F91672 |. FF15 6430F900 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
00F91678 |. 83C4 04  ADD ESP,4 
00F9167B |> 5D   POP EBP 
00F9167C \. C3   RETN 

正如你可以清楚地看到它们之间略有差别:

  • 如果条件得不到满足,他们的行为完全一样的(从而以相同的速度执行)

  • 如果条件满足,在Test1我们必须执行多一个跳跃(00F9164B - JMP SHORT 00F9164F

=>Test2从理论上讲,如果代码编译时没有进行优化,速度会更快,因为编译器会输出一个真实的循环,用于Test1


这是不成熟的优化吗? 绝对!

2

在汇编程序中输出代码并查看它是否与编译器相同(更有可能的是,编译器将对逻辑上相同的机器代码进行优化)。几乎总是编写可读和可维护的代码比担心诸如此类的细节更重要。随着现代编译器能够优化这种简单的情况,除了以最可读的方式编写代码之外,没有什么理由做任何事情了,在这种情况下,我认为将代码编写为if语句表明您的意图向您的其他读者代码远远好于while + break的组合。

8

逻辑上它们是相同的。编译器可能会写出相同的代码。

您应该专注于代码的清晰度,而不是考虑在昏迷的希望中编写混淆代码,以使代码更快。

1
while(x){ 

    //stuff 
    break; 
} 

如果您只对给定条件执行一次操作,上面的代码似乎不合理。这就是为什么如果在这种情况下声明更可取!至于速度差异,我真的怀疑其中一个的重要优势。在地点的使用while循环的if语句是可怕的:

if(condition) 
{ 
    // do stuff 
} 
else if(another_condition) 
{ 
    // do stuff 
} 
else 
{ 
    // do stuff 
} 

这里是一个使用while循环等价的:

while(condition) 
{ 
    // do stuff 
    break; 
} 
while(!condition && another_condition) 
{ 
    // do stuff 
    break; 
} 
while(!condition && !another_condition) 
{ 
    // do stuff 
    break; 
} 

做你的团队一个忙,让你的代码可读性:-)

+0

但我的代码将是唯一的! ;)开玩笑 – Vider7CC

+0

独特并不总是一件好事:) – pcnThird

2

这是一样的。虽然在理论上,while()增加了一个jmp比if if

+0

为什么这样?这个额外的跳跃在哪里? –

+0

@DavidHeffernan'break'后,如果编译器没有优化,它仍然需要跳转到条件。虽然它将永远不会被执行,因为'break' –

+0

编译器只会在它是垃圾时才写出它。如果你关心性能,为什么你会使用不做优化的垃圾编译器? –

1

他们有简单的不同的目的。

if是一个选择语句

while是循环语句。

而且他们应该相应地用于他们的目的。

+1

问题的上下文表明它在询问性能方面的差异,而不是一般性问题。 – BartoszKP

1

如果在第一次迭代中断开while循环,则while循环将充当if语句。

但是你不应该为此目的使用while循环,因为它的目的是循环。

-1

因此,以下可能会给出相同的结果,因为for是被C预处理器修改为一段时间。尽管......其他人对清晰度的评价

for(;x;){ 
    //stuff 
    break; 
} 
+0

如果你没有回答这个问题,那么请把它作为评论。谢谢。 –