如果和同时中断之间的区别

Difference between if and while break

本文关键字:之间 区别 中断 如果      更新时间:2023-10-16

两者之间有区别吗

if(x){
   //stuff
}

while(x){
   //stuff
   break;
}

其中一个更快吗?

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

您应该专注于代码的清晰度,而不是考虑编写混淆代码,希望它可能会更快。

让我们找出答案:

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

使用 VC Nov 2013 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 编译器生成了相同的代码。但如果禁用优化,情况并非如此:

测试1

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

测试2

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

如果代码在没有 optimizatzion 的情况下编译,=> Test2 理论上会更快,因为编译器输出了一个 Test1 的真实循环。


这是过早的优化吗?绝对!

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

是一样的。

虽然理论上 while() 比 if

jmp=">

它们的目的只是不同。

if是选择语句

while是一个迭代语句。

它们应该根据其目的使用。

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

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

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;
}

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

因此,

以下内容可能会给出相同的结果,因为 for 被 C 预处理器修改为一段时间。不过,其他人对清晰度的看法...

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