Long version...

A co-worker asserted today after seeing my use of while (1) in a Perl script that for (;;) is faster. I argued that they should be the same hoping that the interpreter would optimize out any differences. I set up a script that would run 1,000,000,000 for loop iterations and the same number of while loops and record the time between. I could find no appreciable difference. My co-worker said that a professor had told him that the while (1) was doing a comparison 1 == 1 and the for (;;) was not. We repeated the same test with the 100x the number of iterations with C++ and the difference was negligible. It was however a graphic example of how much faster compiled code can be vs. a scripting language.

Short version...

Is there any reason to prefer a while (1) over a for (;;) if you need an infinite loop to break out of?

Note: If it's not clear from the question. This was purely a fun academic discussion between a couple of friends. I am aware this is not a super important concept that all programmers should agonize over. Thanks for all the great answers I (and I'm sure others) have learned a few things from this discussion.

Update: The aforementioned co-worker weighed in with a response below.

Quoted here in case it gets buried.

It came from an AMD assembly programmer. He stated that C programmers (the poeple) don't realize that their code has inefficiencies. He said today though, gcc compilers are very good, and put people like him out of business. He said for example, and told me about the while 1 vs for(;;). I use it now out of habit but gcc and especially interpreters will do the same operation (a processor jump) for both these days, since they are optimized.

hippietrail's user avatar

hippietrail

17.3k21 gold badges115 silver badges181 bronze badges

asked May 20, 2009 at 2:34

Copas's user avatar

20

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?

answered May 20, 2009 at 2:54

bdonlan's user avatar

7 Comments

try with B::Deparse, deparsing an infinite for loop returns a while loop :P

"In perl, they result in the same opcodes"... yes, but which is faster? :-)

I love that gcc substituted puts() for printf(), since there is only one argument and therefore nothing to format -- faster and more secure! (gcc also checks formatting tags against the variable argument list.)

@the Tin Man: they're equivalent, because the computer does the same exact operations :P

@snap, it's not 'completely' incorrect, it's just focusing on the runtime costs. I can't imagine what kind of situation would result in the parsing time of infinite loops being the key deciding factor in how fast your program runs

There's not much reason to prefer one over the other. I do think that while(1) and particularly while(true) are more readable than for(;;), but that's just my preference.

answered May 20, 2009 at 2:38

Bill the Lizard's user avatar

6 Comments

#define EVER ;; for(EVER) I've always find that kind of amusing.

Both seem more readable on the surface, but I try not to define new keywords for my maintenance programmer (usually me) to scratch his head over.

@Bill the Lizard You can still read it out aloud as for (ever) ;)

I think that PC-Lint warns for while(true), and does not for for(;;).

"I try not to define new keywords for my maintenance" — if only more people took that attitude I wouldn’t be clutching at all these inane and magical sleight-of-hand shenanigans every time I turned around!

Using GCC, they both seem to compile to the same assembly language:

L2:
        jmp     L2

answered May 20, 2009 at 2:48

Martin Cote's user avatar

1 Comment

Using GCC with the -S option (assemble, do not link)

There is no difference according to the standard. 6.5.3/1 has:

The for statement

for ( for-init-statement ; conditionopt ; expressionopt ) statement

is equivalent to

{
  for-init-statement
  while ( condition ) {
    statement
    expression ;
  }
}

And 6.5.3/2 has:

Either or both of the condition and the expression can be omitted. A missing condition makes the implied while clause equivalent to while(true).

So according to the C++ standard the code:

for (;;);

is exactly the same as:

{
  while (true) {
    ;
    ;
  }
}

Chris Jefferson's user avatar

answered May 20, 2009 at 10:58

Richard Corden's user avatar

3 Comments

That doesn't pertain to the generated code or performance at all. The standard only defines functionality. Of course, performance will be the same.

I don't believe it's true that a difference in performance violates the as-if rule. If it were, then compilers would not be permitted to speed up your code under the as-if rule, for example by re-ordering independent statements. Compilers in fact do exactly that. But my copy of the standard is way upstairs.

The difference between for and while is that the condition in for is optional while the condition in while is mandatory. Therefore while() will not compile while for(;;) does.

The Visual C++ compiler used to emit a warning for

while (1) 

(constant expression) but not for

for (;;)

I've continued the practice of preferring for (;;) for that reason, but I don't know if the compiler still does that these days.

osgx's user avatar

osgx

95.4k58 gold badges391 silver badges531 bronze badges

answered May 20, 2009 at 4:41

sean e's user avatar

5 Comments

the warning is probably becuase you used while(1) instead of while(true)

Yes, the warning is still present for both 1 and true. That is the reason why I always use for (;;)

@ElvissStrazdins The documentation for Visual Studio now says C4127 doesn't emit a warning for while(1) or while(true).

The docs now state: "Because of their common idiomatic usage, beginning in Visual Studio 2015 update 3, trivial constants such as 1 or true do not trigger the warning, unless they are the result of an operation in an expression."

for(;;) is one less character to type if you want to go in that direction to optimize things.

osgx's user avatar

osgx

95.4k58 gold badges391 silver badges531 bronze badges

answered May 20, 2009 at 2:47

Chris Bartow's user avatar

2 Comments

Good to know for golfing. Otherwise a poor reason to choose a syntax.

@AdamBellaire Terseness often increases readability, above a certain skill threshold.

Turbo C with this old compilers for(;;) results in faster code then while(1).

Today gcc, Visual C (I think almost all) compilers optimize well, and CPUs with 4.7 MHz are rarely used.

In those days a for( i=10; i; i-- ) was faster than for( i=1; i <=10; i++ ), because compare i is 0, results in a CPU-Zero-Flag conditional Jump. And the Zero-Flag was modified with the last decrement operation ( i-- ), no extra cmp-operation is needed.

    call    __printf_chk
    decl    %ebx          %ebx=iterator i 
    jnz     .L2
    movl    -4(%ebp), %ebx
    leave

and here with for(i=1; i<=10; i++) with extra cmpl:

    call    __printf_chk
    incl    %ebx
    cmpl    $11, %ebx
    jne     .L2
    movl    -4(%ebp), %ebx
    leave

chue x's user avatar

chue x

18.9k8 gold badges60 silver badges71 bronze badges

answered Apr 23, 2012 at 7:13

Lutz L.'s user avatar

Comments

For all the people arguing you shouldn't use indefinte while loops, and suggesting daft stuff like using open goto's ( seriously, ouch )

while (1) {
     last if( condition1 );
     code();
     more_code(); 
     last if( condition2 ); 
     even_more_code(); 
}

Can't really be represented effectively any other way. Not without creating an exit variable and doing black magic to keep it synced.

If you have a penchant for the more goto-esque syntax, use something sane that limits scope.

flow: { 

   if ( condition ){ 
      redo flow;
   }
   if ( othercondition ){ 
       redo flow;
   }
   if ( earlyexit ){ 
       last flow;
   }
   something(); # doesn't execute when earlyexit is true 
}

Ultimately Speed is not that important

Worring about how effective speed wise different looping constructs are is a massive waste of time. Premature optimization through and through. I can't think of any situation I've ever seen where profiling code found bottlenecks in my choice of looping construct.

Generally its the how of the loop and the what of the loop.

You should "optimize" for readability and succinctness, and write whatever is best at explaining the problem to the next poor sucker who finds your code.

If you use the "goto LABEL" trick somebody mentioned, and I have to use your code, be prepared to sleep with one eye open, especially if you do it more than once, because that sort of stuff creates horrifically spaghetti code.

Just because you can create spaghetti code doesn't mean you should

answered May 20, 2009 at 4:46

Kent Fredric's user avatar

Comments

If compiler doesn't do any optimization, for(;;) would always be faster than while(true). This is because while-statement evaluates the condition everytime, but for-statement is an unconditional jump. But if compiler optimizes the control flow, it may generate some opcodes. You can read disassembly code very easily.

P.S. you could write a infinite loop like this:

#define EVER ;;
  //...
  for (EVER) {
    //...
  }

chue x's user avatar

chue x

18.9k8 gold badges60 silver badges71 bronze badges

answered Mar 25, 2012 at 15:13

silverbullettt's user avatar

1 Comment

In the modern day and age shouldn't EVER be replaced with EVS (teenage speak)! Seriously though I just simply use for(;;){}. I read online a long time ago about the differences between the two (when I was younger and didn't actually know they are the same) and just stuck with what I read.

From Stroustrup, TC++PL (3rd edition), §6.1.1:

The curious notation for (;;) is the standard way to specify an infinite loop; you could pronounce it "forever". [...] while (true) is an alternative.

I prefer for (;;).

answered Feb 2, 2010 at 8:54

Hans W's user avatar

Comments

I heard about this once.

It came from an AMD assembly programmer. He stated that C programmers (the people) don't realize that their code has inefficiencies. He said today though, gcc compilers are very good, and put people like him out of business. He said for example, and told me about the while 1 vs for(;;). I use it now out of habit but gcc and especially interpreters will do the same operation (a processor jump) for both these days, since they are optimized.

chue x's user avatar

chue x

18.9k8 gold badges60 silver badges71 bronze badges

answered Sep 28, 2010 at 16:35

Jimmie Clark's user avatar

Comments

In an optimized build of a compiled language, there should be no appreciable difference between the two. Neither should end up performing any comparisons at runtime, they will just execute the loop code until you manually exit the loop (e.g. with a break).

answered May 20, 2009 at 2:39

Charlie's user avatar

Comments

Just came across this thread (although quite a few years late).

I think I found the actual reason why "for(;;)" is better than "while(1)".

according to the "barr coding standard 2018"

Kernighan & Ritchie long ago recommended for (;;) , which has the additional benefit
of insuring against the visually-confusing defect of a while (l); referencing a variable ‘l’.

basically, this is not a speed issue but a readability issue. Depending on the font/print of code the number one(1) in a while may look like a lower case letter l.

i.e 1 vs l. (in some fonts these look identical).

So while(1) may look like some while loop dependent on the variable letter L.

while(true) may also work but in some older C and embedded C cases true/false are not yet defined unless stdbool.h is included.

answered Sep 6, 2018 at 9:55

Nick Law's user avatar

2 Comments

I would say the issue in your code would be that you have a variable named l, not that 1 and l can look similar.

Agreed, I know the Barr coding standard also says elsewhere that variables must be at least 3 characters even in for loops. i.e no i++ etc. in a for loop. I tend to think that may be a bit much though. While typing I am also noticing it's not just the letter L that looks like a 1. The letter i which is commonly used as a variable may also cause issues.

I'm surprised no one has offered the more direct form, corresponding to the desired assembly:

forever:
     do stuff;
     goto forever;

answered Aug 17, 2010 at 19:10

Phil Miller's user avatar

2 Comments

Dose that not end up with the same machine code as while 1 or for (;;) in say c?

One other shortcoming of that approach: it violates encapsulation by not enclosing the loop in a block -- thus any variables declared in the loop are available outside the loop. (Of course, you could { forever: do stuff; goto forever; })

I am surprised that nobody properly tested for (;;) versus while (1) in perl!

Because perl is interpreted language, the time to run a perl script does not only consist of the execution phase (which in this case is the same) but also of the interpretation phase before execution. Both of these phases have to be taken in account when making a speed comparison.

Luckily perl has a convenient Benchmark module which we can use to implement a benchmark such as follows:

#!/usr/bin/perl -w

use Benchmark qw( cmpthese );

sub t_for   { eval 'die; for (;;) { }'; }
sub t_for2  { eval 'die; for (;;)  { }'; }
sub t_while { eval 'die; while (1) { }'; }

cmpthese(-60, { for => \&t_for, for2 => \&t_for2, while => \&t_while });

Note that I am testing two different versions of the infinite for loop: one which is shorter than the while loop and another one which has an extra space to make it the same length as the while loop.

On Ubuntu 11.04 x86_64 with perl 5.10.1 I get the following results:

          Rate   for  for2 while
for   100588/s    --   -0%   -2%
for2  100937/s    0%    --   -1%
while 102147/s    2%    1%    --

The while loop is clearly the winner on this platform.

On FreeBSD 8.2 x86_64 with perl 5.14.1:

         Rate   for  for2 while
for   53453/s    --   -0%   -2%
for2  53552/s    0%    --   -2%
while 54564/s    2%    2%    --

While loop is the winner here too.

On FreeBSD 8.2 i386 with perl 5.14.1:

         Rate while   for  for2
while 24311/s    --   -1%   -1%
for   24481/s    1%    --   -1%
for2  24637/s    1%    1%    --

Surprisingly the for loop with an extra space is the fastest choice here!

My conclusion is that the while loop should be used on x86_64 platform if the programmer is optimizing for speed. Obviously a for loop should be used when optimizing for space. My results are unfortunately inconclusive regarding other platforms.

answered Sep 3, 2011 at 17:58

snap's user avatar

5 Comments

The conclusion is blatantly wrong. Benchmark has its limitations and cannot be used to distinguish fast from slow if the results are within 7% of each other. Moreover, you have not tested the difference between the for and while loops because each sub will die before reaching the loops themselves. And since when did the amount of whitespace matter to the Perl interpreter? Sorry, but the analysis is extremely flawed.

@Zaid, Thanks for your comments! Would you mind posting your own answer so that everyone can learn from that? :) The die is there in my code because my intention is to test only the compilation time difference. As others have already pointed out the resulting byte-code is identical, thus there is no point in testing that. Surprisingly the amount of white space seems to make a small difference in this case in my testing environments. It might have something to do with how the characters end up getting aligned in memory or something similar...

I don't need to post an answer because what I would say has already been mentioned by bdonlan. And even if you're comparing compile times, the numbers that Benchmark are inconclusive. Don't trust that 1% difference at all!

Only 60 iterations? Run tests for like 5 minutes so as to get more accurate relative times.

-60 runs the test for 60 seconds.

In theory, a completely naive compiler could store the literal '1' in the binary (wasting space) and check to see if 1 == 0 every iteration (wasting time and more space).

In reality, however, even with "no" optimizations, compilers will still reduce both to the same. They may also emit warnings because it could indicate a logical error. For instance, the argument of while could be defined somewhere else and you not realize it's constant.

answered Apr 16, 2010 at 14:23

Nick T's user avatar

Comments

while(1) is an idiom for for(;;) which is recognized by most compilers.

I was glad to see that perl recognizes until(0), too.

chue x's user avatar

chue x

18.9k8 gold badges60 silver badges71 bronze badges

answered May 21, 2009 at 12:42

J M D's user avatar

2 Comments

In what situation would until(0) be helpful?

until() is the opposite of while() just as unless() is the opposite of if(). As suggested eslewhere in this thread, one might write: do { something... } while (! condition) An alternative might be until (condition) { something }

To summarize the for (;;) vs while (1) debate it is obvious that the former was faster in the days of older non-optimizing compilers, that is why you tend to see it in older code bases such as Lions Unix Source code commentary, however in the age of badass optimizing compilers those gains are optimized away coupling that with the fact that the latter is easier to understand than the former I believe that it would be more preferable.

answered Jun 13, 2016 at 10:06

redbandit's user avatar

1 Comment

The people speculating that a compiler didn't know how to create efficient assembly for while(true) didn't provide any evidence of that.

I would think that both are the same in terms of performance. But I would prefer while(1) for readability but I question why you need an infinite loop.

answered May 21, 2009 at 5:13

bichonfrise74's user avatar

1 Comment

I suggest you start writing some code more often if you can't think of a reason to have an infinite loop.

They are the same. There are much more important questions to ponder.


My point which was implied but not explicitly made above, is that a decent compiler would generate the exact same code for both loop forms. The bigger point is that the looping construct is a minor part of the run time of any algorithm, and you must first ensure that you have optimized the algorithm and everything else related to it. Optimizing your loop construct should absolutely be at the bottom of your priority list.

E_net4's user avatar

E_net4

30.6k13 gold badges119 silver badges155 bronze badges

answered May 20, 2009 at 2:38

Mark Ransom's user avatar

8 Comments

No links or explanation. Unhelpful, subjective and a little condescending.

well no proof but he is right. They both call the Opcode for jumping when false. (which would make it the same as goto but no one likes gotos)

I was unaware that only important questions where to be asked, my mistake was my first question.

Yes, I admit it is condescending. But seriously, even without any proof it is obvious that they are going to be in the same ballpark speedwise; if the question was about style there would be something to argue about. I was trying to make the point that on the list of things to worry about, this should really be at the bottom of the list.

I wasn't trying to be a jerk. I was trying to make a point. When I posted it I was trying for a kind of dark humor, and it is obvious that I failed; for that I apologize.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.