While (1) VS. for (;;) Is There a Speed Difference

while (1) Vs. for (;;) Is there a speed difference?

In perl, they result in the same opcodes:

$ perl -MO=Concise -e 'for(;;) { print "foo\n" }'
a <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 2 -e:1) v ->3
9 <2> leaveloop vK/2 ->a
3 <{> enterloop(next->8 last->9 redo->4) v ->4
- <@> lineseq vK ->9
4 <;> nextstate(main 1 -e:1) v ->5
7 <@> print vK ->8
5 <0> pushmark s ->6
6 <$> const[PV "foo\n"] s ->7
8 <0> unstack v ->4
-e syntax OK

$ perl -MO=Concise -e 'while(1) { print "foo\n" }'
a <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 2 -e:1) v ->3
9 <2> leaveloop vK/2 ->a
3 <{> enterloop(next->8 last->9 redo->4) v ->4
- <@> lineseq vK ->9
4 <;> nextstate(main 1 -e:1) v ->5
7 <@> print vK ->8
5 <0> pushmark s ->6
6 <$> const[PV "foo\n"] s ->7
8 <0> unstack v ->4
-e syntax OK

Likewise in GCC:

#include <stdio.h>

void t_while() {
while(1)
printf("foo\n");
}

void t_for() {
for(;;)
printf("foo\n");
}

.file "test.c"
.section .rodata
.LC0:
.string "foo"
.text
.globl t_while
.type t_while, @function
t_while:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
.L2:
movl $.LC0, %edi
call puts
jmp .L2
.LFE2:
.size t_while, .-t_while
.globl t_for
.type t_for, @function
t_for:
.LFB3:
pushq %rbp
.LCFI2:
movq %rsp, %rbp
.LCFI3:
.L5:
movl $.LC0, %edi
call puts
jmp .L5
.LFE3:
.size t_for, .-t_for
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zR"
.uleb128 0x1
.sleb128 -8
.byte 0x10
.uleb128 0x1
.byte 0x3
.byte 0xc
.uleb128 0x7
.uleb128 0x8
.byte 0x90
.uleb128 0x1
.align 8
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1
.LASFDE1:
.long .LASFDE1-.Lframe1
.long .LFB2
.long .LFE2-.LFB2
.uleb128 0x0
.byte 0x4
.long .LCFI0-.LFB2
.byte 0xe
.uleb128 0x10
.byte 0x86
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x6
.align 8
.LEFDE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3
.LASFDE3:
.long .LASFDE3-.Lframe1
.long .LFB3
.long .LFE3-.LFB3
.uleb128 0x0
.byte 0x4
.long .LCFI2-.LFB3
.byte 0xe
.uleb128 0x10
.byte 0x86
.uleb128 0x2
.byte 0x4
.long .LCFI3-.LCFI2
.byte 0xd
.uleb128 0x6
.align 8
.LEFDE3:
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits

So I guess the answer is, they're the same in many compilers. Of course, for some other compilers this may not necessarily be the case, but chances are the code inside of the loop is going to be a few thousand times more expensive than the loop itself anyway, so who cares?

while(true) / while(1) vs. for(;;)

There is no difference once the program is compiled.

Here are some excerpts from three C programs and the corresponding generated assembly for all of them.

Let's try the for loop first:

#include <stdio.h>
int main(){
for(;;)
printf("This is a loop\n");
return 0;
}

Now we will try the while loop:

#include <stdio.h>
int main(){
while(1)
printf("This is a loop\n");
return 0;
}

A terrible solution, the goto loop:

#include <stdio.h>
int main(){
alpha:
printf("This is a loop\n");
goto alpha;
return 0;
}

Now, if we examine the generated assemblies, using the command gcc -S loop.c, they all look like this (I didn't see any reason to post them separately, since they are identical):

   .file "loop.c"
.section .rodata
.LC0:
.string "This is a loop"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
.L2:
movl $.LC0, (%esp)
call puts
jmp .L2
.size main, .-main
.ident "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
.section .note.GNU-stack,"",@progbits

This part is the loop. It declares a label, copies the address to the string into a register, calls a routine called puts, and jumps back to the label:

.L2:
movl $.LC0, (%esp)
call puts
jmp .L2

Since they all do exactly the same thing, clearly there is no technical advantage of any of them (at least if you are using gcc).

However, people have opinions, and may favor one over the others for whatever reason. Since for(;;) is only seven characters long, it is easier to type (this is my preference). On the other hand, while(1) gives the illusion of a test which always evaluates to true, which some may find more intuitive. Only a few crazy people like the goto solution best.

Edit: Apparently some compilers might produce a warning for while(1) because the condition is always true, but such warnings can be easily disabled and have no effect on the generated assembly.

What is the difference between for(;;) and while(1)?

The difference with these is that many compilers will warn about while(true) ("constant expression used as loop expression"), while none I know of warn about for(;;).

They should generate the same code, though.

Which loop is faster, while or for?

That clearly depends on the particular implementation of the interpreter/compiler of the specific language.

That said, theoretically, any sane implementation is likely to be able to implement one in terms of the other if it was faster so the difference should be negligible at most.

Of course, I assumed while and for behave as they do in C and similar languages. You could create a language with completely different semantics for while and for

Is there a speed difference between an if check and a while check

From a performance point of view, the difference is negligible. And any decent compiler will transform both snippets of your code to (nearly) identical assembly depending on your optimization settings.

From a design point of view, it makes no sense to have two loops or a nested loop and an if inside loop in the first place. As you could easily rewrite your condition in just one loop.

When it comes to performance comparison questions the first thing to do is benchmark the code yourself. Godbolt is a great website to check the produced assembly differences for different codes and compilers.

Really though, unless you're working with very very very specific software and hardware that can not afford to delay a few clock cycles then this kind of optimization is premature. Unless, you know your platform and code very well the compiler will outsmart you in generating fast assembly. Just focus on getting correct and readable code.

Performance difference between for, while and do while loop?

The overall semantics of all three iteration statements is the same once they have been compiled into binary code.

They just provide a different taste over the same thing. Performance depends on:

  • the complexity of the body of the loop
  • the complexity of calculating the end condition / next iteration step

Since they all provide both of them there is no performance difference per se in any of them. Unless you consider small irrelevant things that you shouldn't care in any case.

There could be some optimization tricks that can be done according to the kind of loop but you shouldn't rely on them, even because they could be compiler dependent, so meaningless from your point of view.

Are while loops more efficient than for loops

All loops follow the same template:

{
// Initialize
LOOP:
if(!(/* Condition */) ) {
goto END
}

// Loop body

// Loop increment/decrement
goto LOOP
}
END:

Therefor the two loops are the same:

// A
for(int i=0; i<10; i++) {
// Do stuff
}

// B
int i=0;
while(i < 10) {
// Do stuff
i++;
}

// Or even
int i=0;
while(true) {
if(!(i < 10) ) {
break;
}

// Do stuff
i++;
}

Both are converted to something similar to:

{
int i=0;
LOOP:
if(!(i < 10) ) {
goto END
}

// Do stuff

i++;
goto LOOP
}
END:

Unused/unreachable code will be removed from the final executable/library.

Do-while loops skip the first conditional check and are left as an exercise for the reader. :)

Strange memory usage in while(1) vs. for(;;)

It's an implementation detail. With the for loop, PHP probably uses some space to store three pointers, one for the for intialization, one for the incrementation, and one for the stop condition. If you're on a 64-bit system, then this accounts for the 64 * 3 = 192 extra bits you're seeing. Of course, it's hard to tell if I'm right without looking at the actual code.



Related Topics



Leave a reply



Submit