Syntactically I see that they loop indefinitely until a break statement is reached, but are they compiled to the same thing? Is the for slightly faster because it doesn't have a condition to check? Aside from code readability, is there even a difference?
-
See http://stackoverflow.com/questions/2288856/when-implementing-an-infinite-loop-is-there-a-difference-in-using-while1-vs-fo – Bertrand Marron Jul 27 '10 at 20:17
-
This is a good question. I find it interesting to see that the compiler optimizes the code down to a do while loop in the example code I tried this with. – Wil P Jul 27 '10 at 20:23
-
1`for(;;)` is A) written by former C coders, and B) four characters shorter :) – hobbs Jul 29 '10 at 04:26
7 Answers
Given this input:
private static void ForLoop()
{
int n = 0;
for (; ; )
{
Console.WriteLine(n++);
}
}
private static void WhileLoop()
{
int n = 0;
while (true)
{
Console.WriteLine(n++);
}
}
...you get this output:
.method private hidebysig static void ForLoop() cil managed
{
// Code size 14 (0xe)
.maxstack 3
.locals init ([0] int32 n)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: ldc.i4.1
IL_0005: add
IL_0006: stloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: br.s IL_0002
} // end of method Program::ForLoop
.method private hidebysig static void WhileLoop() cil managed
{
// Code size 14 (0xe)
.maxstack 3
.locals init ([0] int32 n)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: ldc.i4.1
IL_0005: add
IL_0006: stloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: br.s IL_0002
} // end of method Program::WhileLoop
Remarkably similar, I would say (identical, even).

- 155,851
- 29
- 291
- 343
-
Unless I'm missing something, they are *identical*, outside of the comments and identifier names. – T.E.D. Jul 27 '10 at 20:11
-
-
18Hmm, there's a difference on line 5... oh, wait, no that's a spot on my monitor ;) – Mike Caron Jul 27 '10 at 20:12
-
8
-
2@Steven: I certainly hope not. We are satisfying our curiosity. At least I am. – Fredrik Mörk Jul 27 '10 at 20:30
-
There are not a lot of examples of the C# compiler optimizing the code. Normally the JIT compiler does the job. This is one of them though. – Hans Passant Jul 27 '10 at 20:43
-
@Steven, one infinite loop could terminate earlier than the other, if it makes more excessive contributions to the eventual heat decay of the universe than the other loop. – Nathan Ernst Jul 27 '10 at 21:16
-
@Nathan you can't really rely on that behaviour, though. Currently, it's theorized that the loop will terminate, but it's also possible that in the future the universe will throw a `CausalityViolatedException` instead. – Mike Caron Jul 27 '10 at 21:29
-
@Fredrik: I would hope not, as well, but look at Nathan's response. :-) – Steven Sudit Jul 27 '10 at 22:06
In modern compilers, absolutely nothing.
Historically, however, for(;;)
was implemented as a single jump, while while(true)
also had a check for true.
I prefer while(true)
, since it makes it more clear what I am doing.

- 14,351
- 4
- 49
- 77
-
2+1 absolutely. `while(true)` is much more clear than `for(;;)`. What am I waiting for, anyway? – Matthew Jones Jul 27 '10 at 20:07
-
1I heartily agree that you should pick the one you think is clearer, although I might disagree on which one that is... – T.E.D. Jul 27 '10 at 20:08
-
2
-
5
-
The world might or might not end, but using `goto` can disable all optimizations. – Steven Sudit Jul 27 '10 at 20:20
-
You sure about that? How do you think the compiler implements flow control? – Mike Caron Jul 27 '10 at 20:24
-
6I don't think the world would end if we used `goto`, but it might abruptly jump to a new location in the universe. – Dr. Wily's Apprentice Jul 27 '10 at 20:38
-
@Mike: The compiler does use branches and jumps, but in order for it to optimize your code, you have to avoid `goto`. – Steven Sudit Jul 27 '10 at 20:39
-
@Steven: I highly doubt that. There are reasons to avoid `goto`, but optimization is not one of them. The C# compiler doesn't do any heavy optimization, relying on the CLR to optimize the JIT'd code. In this situation, a user-specified `goto` and a copiler specified `goto` are exactly the same. (And, you can look that up) – Mike Caron Jul 27 '10 at 21:06
-
@Mike: You might be right about C#, but I know this was the case with MSVC++ and a number of other C++ compilers. – Steven Sudit Jul 28 '10 at 00:40
-
I haven't examined the output code, but there should be no difference whatsoever. Any decent compiler will do simple enough loop optimization to see that the condition is a constant expression, and thus doesn't need checking every iteration.
If one is faster than the other, the C# compiler writers need something 'splained to them...

- 44,016
- 10
- 73
- 134
If I might, I'd suggest that you look at a somewhat different question. If you're using either of these often enough to care, you're probably structuring your code poorly. While there are things like embedded systems that really do run forever, loops in most normal code do not. Writing a loop that claims to run forever usually means you've hidden the exit condition for the loop somewhere inside, with some other control flow (e.g., if (whatever) break;
) as the real exit from the loop.
That can and usually should be avoided. While there are situations where break
statements make sense, they should generally be to handle unusual situations, not for writing a loop that says one thing but does another (i.e., says "run forever", but really does "run until condition is met").

- 476,176
- 80
- 629
- 1,111
-
Me neither. When I was first learning to program in PL/I (I don't know if it even had a 'break' statement) the pattern was "read line of file; while it's not the end-marker, do the loop, which ends with reading the next line". That seems a violation of "don't repeat yourself". I would suggest that reading the line once, at the start of the loop, and exiting if it's an end-marker, is a better style. – supercat Jul 27 '10 at 20:25
-
@supercat: I agree, but it doesn't justify anything. You should be doing `while (file.getline())`, not `for (;;) if (!file.getline()) break;` – Jerry Coffin Jul 27 '10 at 20:31
-
@supercat: Yes, it's often cleanest to put the test into the *middle* of the loop and break out of it when it fails. – Steven Sudit Jul 27 '10 at 20:37
-
@Jerry: That's a plausible example, but hardly the only way things work. The sentinel could instead be a specific value, such as a "0". – Steven Sudit Jul 27 '10 at 20:38
-
@Steven: The value of the sentinel rarely (if ever) matters. Something like `for (;;) { x = next_value(); if (x == sentinel) break; process(x); }` can essentially always be converted to something like `while ((x=next_value()) != sentinel ) process(x);`. – Jerry Coffin Jul 27 '10 at 20:45
-
I once wrote an RFC 822 header parser that looped until it hit an empty line, but inside that loop it also had to peek ahead to see if the next line is a continuation and keep looping internally until it concatenated the whole thing. After all that, it had to check that the key/value pair was both syntactically and semantically valid, exiting if not. I suppose it's possible to obfuscate this so as to avoid a `while(true)` but why bother? This is a genuine case of multiple exit criteria that cannot be determined in a single location on top. – Steven Sudit Jul 27 '10 at 21:02
-
My conclusion from this is that avoidance of the infinite loop with internal breaks is a pointless ideal that only *hurts* code quality. – Steven Sudit Jul 27 '10 at 21:03
-
@Steven: I was very careful to say it should "usually" be avoided. Yes, insisting on avoiding it even when it's the only reasonable solution can reduce code quality -- but that's really pretty rare. The *usual* result is an improvement in code quality. – Jerry Coffin Jul 27 '10 at 21:26
-
I'm skeptical even about "usually". In your example, you show assignment and comparison being combined, but that's a bad practice. – Steven Sudit Jul 27 '10 at 22:08
-
1@Jerry Coffin: That while() loop condition exceeds my threshold for how many side-effects an expression can have before it's considered ridiculous. Why bother with a loop body at all? Why not "while ((((x=next_value()) != sentinel) && (process(x),1));"? – supercat Jul 27 '10 at 23:12
-
@Supercat: Because just as the condition for exiting the loop *should* be in the loop condition, other code like `process(x);` that does *not* form part of the condition for exiting the loop should *not* be in the loop condition. "Think before you ask these things!" – Jerry Coffin Jul 28 '10 at 01:53
-
@Jerry Coffin: I was being a little sarcastic; my point was that I dislike writing conditional expressions with excessive side-effects, and I think your example is really pushing things. I don't mind "if" statements that directly check whether a function works, nor do I mind "do {} while(--i);" but side-effect-laden expressions at the top of a loop don't feel right to me. – supercat Jul 28 '10 at 15:27
They compile to the same thing. You can write a test app that implements both methods and then use ILDASM to confirm they IL is identical.

- 1,100
- 2
- 12
- 30
-
3Or you can just look at Fredrik's answer and save yourself the trouble. :) – DarLom Jul 27 '10 at 20:13
A debug assembly complies down to while(true). Use reflector and you can see the results.
static void Main(string[] args)
{
ExecuteWhile();
ExecuteFor();
}
private static void ExecuteFor()
{
for (; ; )
{
Console.WriteLine("for");
string val = Console.ReadLine();
if (string.IsNullOrEmpty(val))
{
Console.WriteLine("Exit for.");
break;
}
}
}
private static void ExecuteWhile()
{
while (true)
{
Console.WriteLine("while");
string val = Console.ReadLine();
if (string.IsNullOrEmpty(val))
{
Console.WriteLine("Exit while.");
break;
}
}
}
Inspecting the ExecuteFor
method in Reflector.
private static void ExecuteFor()
{
while (true)
{
Console.WriteLine("for");
if (string.IsNullOrEmpty(Console.ReadLine()))
{
Console.WriteLine("Exit for.");
return;
}
}
}
An optimized version of the same code produces different results for ExecuteFor
private static void ExecuteFor()
{
do
{
Console.WriteLine("for");
}
while (!string.IsNullOrEmpty(Console.ReadLine()));
Console.WriteLine("Exit for.");
}
For verbosity here is the optimized ExecuteWhile
...
private static void ExecuteWhile()
{
do
{
Console.WriteLine("while");
}
while (!string.IsNullOrEmpty(Console.ReadLine()));
Console.WriteLine("Exit while.");
}

- 3,341
- 1
- 20
- 20
-
Does it really compile down to `while(true)`, or does Reflector decompile it that way? :p – Mark H Jul 27 '10 at 20:18
-
If you look at the IL created from the same assemblies it reads that way. – Wil P Jul 27 '10 at 20:31
As mentioned by others, with any modern compiler, it should make absolutely no difference.
I did a brief test on my computer, timing a couple of operations using one or the other, and they always took pretty much the same time. Of course, because of other processes running, these tests aren't 100% accurate, but if there is a difference in speed (there shouldn't be) then it is a microscopic one.

- 8,220
- 3
- 24
- 30