Endless loop in C/C++ [closed]
Asked Answered
S

12

83

There are several possibilities to do an endless loop, here are a few I would choose:

  • for(;;) {}
  • while(1) {} / while(true) {}
  • do {} while(1) / do {} while(true)

Is there a certain form which one should choose? And do modern compilers make a difference between the middle and the last statement or does it realize that it is an endless loop and skips the checking part entirely?

Edit: as it has been mentioned I forgot goto, but this was done out of the reason that I don't like it as a command at all.

Edit2: I made some grep on the latest versions taken from kernel.org. I does seems as nothing much changed over time (within the Kernel at least) enter image description here

Savona answered 25/11, 2013 at 7:23 Comment(19)
I think you forgot endless: GOTO endless;Incretion
I think you should choose the option that makes the code readable enough like while (true) {}Hagio
@Jite: Nope, that's not an endless loop, it will result in an overflow.Incretion
@Incretion A "stack" overflow. Eh? Eeh?Hygroscope
You forgot the GOTO possibility.Sybyl
@Deck That link is not only for C#, it just contains subjective nonsense with everyone's highly personal opinions.Julio
You could also do a recursive tail-call (assuming your compiler does tail-call optimization). i.e. void loop() { ...; loop(); }.Civility
This has already been asked here: https://mcmap.net/q/18776/-infinite-loops-top-or-bottom-closedHygroscope
it also has been asked on programmers.stackexchange if I remember correctly. Which is right, as imo this is rather opinion based.Chacon
Personally, I try to avoid this construct, and just put the breaking condition in the control statement where it is supposed to go. If I can't get around it, I'll use while(true) though.Twelve
it never skips the checking part unless it is programmmed to do so, or unless something goes wrong.Lancinate
Most of the answers here miss the subtlety that it's usually not a truly endless loop that's being written, merely one whose exit conditions are not tested at the top or bottom of the loop body but in the middle somewhere (which in itself, for good reason, is usually considered something to be avoided). So any text that implies 'forever' is at least an abuse of language, even if most programmers know that 'forever' doesn't mean forever.Corona
I propose #define forever while(1) The issue is that it's not actually endless, it will end on signals/subsystem being terminated. I need a better name for it... until_subsystem_terminates is not as appealing.Statism
@Dmitry. While definitely a possibility, if feel that macros are a horrible way ti achieve the goal as people actually have to look-up the macro definition in order to understand it.Savona
simple grep on linux 4.10.10 kernel sources: 'for(;;)' - 57 occurrences; 'while(true)' - 1; 'while(1)' - 82Carpophore
@shcherbak. That is very interesting. I wonder how those numbers evolved over time.Savona
@Savona , may 'grep -R' and kernel.org be with you :)Carpophore
@shcherbak. I added a graph about that. For whoever is also interested in it.Savona
None of them are guaranteed endless loops in C++. Pick your language, C and C++ are different languages!Rectangular
J
122

The problem with asking this question is that you'll get so many subjective answers that simply state "I prefer this...". Instead of making such pointless statements, I'll try to answer this question with facts and references, rather than personal opinions.

Through experience, we can probably start by excluding the do-while alternatives (and the goto), as they are not commonly used. I can't recall ever seeing them in live production code, written by professionals.

The while(1), while(true) and for(;;) are the 3 different versions commonly existing in real code. They are of course completely equivalent and results in the same machine code.


for(;;)

  • This is the original, canonical example of an eternal loop. In the ancient C bible The C Programming Language by Kernighan and Ritchie, we can read that:

    K&R 2nd ed 3.5:

    for (;;) {
    ...
    }
    

    is an "infinite" loop, presumably to be broken by other means, such as a break or return. Whether to use while or for is largely a matter of personal preference.

    For a long while (but not forever), this book was regarded as canon and the very definition of the C language. Since K&R decided to show an example of for(;;), this would have been regarded as the most correct form at least up until the C standardization in 1990.

    However, K&R themselves already stated that it was a matter of preference.

    And today, K&R is a very questionable source to use as a canonical C reference. Not only is it outdated several times over (not addressing C99 nor C11), it also preaches programming practices that are often regarded as bad or blatantly dangerous in modern C programming.

    But despite K&R being a questionable source, this historical aspect seems to be the strongest argument in favour of the for(;;).

  • The argument against the for(;;) loop is that it is somewhat obscure and unreadable. To understand what the code does, you must know the following rule from the standard:

    ISO 9899:2011 6.8.5.3:

    for ( clause-1 ; expression-2 ; expression-3 ) statement
    

    /--/

    Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.

    Based on this text from the standard, I think most will agree that it is not only obscure, it is subtle as well, since the 1st and 3rd part of the for loop are treated differently than the 2nd, when omitted.


while(1)

  • This is supposedly a more readable form than for(;;). However, it relies on another obscure, although well-known rule, namely that C treats all non-zero expressions as boolean logical true. Every C programmer is aware of that, so it is not likely a big issue.

  • There is one big, practical problem with this form, namely that compilers tend to give a warning for it: "condition is always true" or similar. That is a good warning, of a kind which you really don't want to disable, because it is useful for finding various bugs. For example a bug such as while(i = 1), when the programmer intended to write while(i == 1).

    Also, external static code analysers are likely to whine about "condition is always true".


while(true)

  • To make while(1) even more readable, some use while(true) instead. The consensus among programmers seem to be that this is the most readable form.

  • However, this form has the same problem as while(1), as described above: "condition is always true" warnings.

  • When it comes to C, this form has another disadvantage, namely that it uses the macro true from stdbool.h. So in order to make this compile, we need to include a header file, which may or may not be inconvenient. In C++ this isn't an issue, since bool exists as a primitive data type and true is a language keyword.

  • Yet another disadvantage of this form is that it uses the C99 bool type, which is only available on modern compilers and not backwards compatible. Again, this is only an issue in C and not in C++.


So which form to use? Neither seems perfect. It is, as K&R already said back in the dark ages, a matter of personal preference.

Personally, I always use for(;;) just to avoid the compiler/analyser warnings frequently generated by the other forms. But perhaps more importantly because of this:

If even a C beginner knows that for(;;) means an eternal loop, then who are you trying to make the code more readable for?

I guess that's what it all really boils down to. If you find yourself trying to make your source code readable for non-programmers, who don't even know the fundamental parts of the programming language, then you are only wasting time. They should not be reading your code.

And since everyone who should be reading your code already knows what for(;;) means, there is no point in making it further readable - it is already as readable as it gets.

Julio answered 25/11, 2013 at 9:28 Comment(17)
Your bold text is the very truth.Scrabble
It must be noted that this answer is relevant to C programmers only, as it addresses only C. +1 nevertheless.Palumbo
@Nawaz Ah, I didn't notice. Well, the only difference there is that C++ has a built-in bool as primitive data type, so the remarks about stdbool.h and C99 for while(true) aren't valid in C++. I'll edit the post.Julio
@Lundin: I find this line misleading >> "Instead of making such pointless statements, I'll try to answer this question with facts and references, rather than personal opinions.".......... because at the end all the points you've written are "personal opinions" of XYZ. If you find other answers as "pointless statements", then I don't find anything in your answer, which is different from others!Palumbo
@Nawaz "The personal opinion" of the ISO standard committee working group 14? :) The remark was mainly aimed towards those who'll write "Use for(;;) because I'm random_dude_999 on stack overflow and I say so". The last part of my answer contains personal opinions, but I explicitly labelled as such. Most of the other contents can either be cited from the standard, or are "de facto" statements learnt from experience. For example, any veteran C programmer can vouch for do-while(1) not being used in real code, but it gets hard to find a source to cite for that.Julio
Depending on your audience, #define forever for (;;) may increase readability. I think I've seen it once or twice.Touching
@Julio "it also preaches programming practices that are often regarded as bad or blatantly dangerous in modern C programming" - a reference would be nice. I've been writing C since K&R 1st Edition, and I'd like to know where I'm going wrong..Corona
@user1681572 There's some sites on the net dedicated to point out problems with that book. The main one being that it is so incredibly old, that it was basically written before good programming practice was even invented. No matter, if you have been writing C since ancient times, you need no such reference. Merely open any page in the book and see for yourself. Here is one such example where I dissected some K&R gibberish and tried to turn it into something almost acceptable.Julio
@Julio "it is so incredibly old, that it was basically written before good programming practice was even invented". Well I am obviously incredibly old, and you clearly aren't, otherwise you would know that's not true :-)Corona
@user1681572 Hrm, well... old is a relative term. A human born in the 70s is not (yet) regarded as "old", while a computer (or computer software) from the same time period is considered extremely ancient. The first edition of K&R was released in 1978. It is now 35 years old. The C language, and programming in general, have changed a lot over the years. The 2nd edition of the book merely corrected some of errors, to make it somewhat compatible with C90. The mindset and program design techniques remain extremely ancient, however. Anyway, this discussion is off-topic.Julio
@Julio My point, which is pertinent to the question and even more so to your answer, is that the concept of sound programming practice is much older, and its realization much more subjective, than you seem to think. It doesn't take a leap of imagination to see that if what was regarded 30 years ago as sound is now regarded as bad, then in another 30 years what's now regarded as sound ....Corona
A convenient, widespread way of reading aloud for(;;) is "forever", so in a sense it is more readable than while(true).Lillie
As someone who was already a programmer when K+R's book came out, I am in complete agreement with @user1681572. Aside from OO matters, all of the major elements of what is considered "good modern programming practice" today, already existed and were widely espoused. K+R just didn't agree with them, and as a side-effect ended-up creating a whole dominant programming subculture that would take decades to come back around to what was already known in the 70's.Insecurity
Everything but the bolded remark in this answer is superfluous, but the latter makes the former worth it somehow.Disaffection
@Julio Which compiler are you using? VS2008 does not complain at all about while(true) or while(1), even at warning level 4. There's a different warning about while(i = 1): "assignment in a conditional expression"Pesade
@Pesade Not all compilers give such warnings, they aren't mandated to do so.Julio
You can increase the readability a hundred-fold with #define forever for(;;) :-)Yajairayajurveda
P
38

It is very subjective. I write this:

while(true) {} //in C++

Because its intent is very much clear and it is also readable: you look at it and you know infinite loop is intended.

One might say for(;;) is also clear. But I would argue that because of its convoluted syntax, this option requires extra knowledge to reach the conclusion that it is an infinite loop, hence it is relatively less clear. I would even say there are more number of programmers who don't know what for(;;) does (even if they know usual for loop), but almost all programmers who knows while loop would immediately figure out what while(true) does.

To me, writing for(;;) to mean infinite loop, is like writing while() to mean infinite loop — while the former works, the latter does NOT. In the former case, empty condition turns out to be true implicitly, but in the latter case, it is an error! I personally didn't like it.

Now while(1) is also there in the competition. I would ask: why while(1)? Why not while(2), while(3) or while(0.1)? Well, whatever you write, you actually mean while(true) — if so, then why not write it instead?

In C (if I ever write), I would probably write this:

while(1) {} //in C

While while(2), while(3) and while(0.1) would equally make sense. But just to be conformant with other C programmers, I would write while(1), because lots of C programmers write this and I find no reason to deviate from the norm.

Palumbo answered 25/11, 2013 at 7:26 Comment(17)
for(;;) is very clear, I have yet to meet another (experienced) programmer that does not know that it resembles an infinite loop. Plus it's less characters to write.Shift
@Shift But it includes a crying face.Tropo
@Tropo The loop terminates when the tears stop.Hygroscope
@miguel.martin: You should re-read your comment again, to know why for(;;) is comparatively less clear >> "for(;;) is very clear, I have yet to meet another (experienced) programmer that does not know that it resembles an infinite loop." (emphasized mine). Why did you feel the need to write "(experienced)" in your comment? You write code only for experienced programmers?Palumbo
@Nawaz mostly out of two reason, first less keystrokes, second logically one does mean true normaly. So readability.Savona
@Nawaz @Savona Where are you seeing 1 in for(;;)? Surely it is ambiguous. If we assume that a for loop tests for a condition being true before each iteration, do we consider a blank condition true or false?Parsimony
@JimmyThompson: Did I say I saw 1 in for(;;)?Palumbo
@Nawaz No, that was in reference to Magu's comment, not yours.Parsimony
@JimmyThompson: I'm wondering why is it directed to me as well (I see my name there!).Palumbo
@Nawaz Apologies, seemed appropriate since it was a reply to a reply aimed at a comment you made.Parsimony
To make the confussion complete, I was answering to the post and not the comment...Savona
programmers.stackexchange.com/questions/119018/… has some interesting pointsChacon
@stijn: I've been writing while(true) for last 5 years and my compilers (even with all warning enabled), don't give any warning. Probably what you said, was true some time back in past. I don't write while(1) though, because I don't code in C anymore, and in C++, I find while(true) better.Palumbo
Curious what would be wrong with #define true 1 in C?Inexpiable
My guess is that while(true) is better because it is literally "readable" in other words you can read it aloud, pronounce it. And it sounds just like it looks: "WHILE TRUE"Silverware
@Nawaz I added in experienced, just incase you happened to mention beginners learning how to program and not knowing what for(;;) means.Shift
while(1){}; us used, because standard C can't compile while(){}; . Additionally value1==value2 returns 1 in standard C, not C++ of others modern.Araarab
C
35

In an ultimate act of boredom, I actually wrote a few versions of these loops and compiled it with GCC on my mac mini.

the while(1){} and for(;;) {} produced same assembly results while the do{} while(1); produced similar but a different assembly code

heres the one for while/for loop

    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp2:
    .cfi_def_cfa_offset 16
Ltmp3:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp4:
    .cfi_def_cfa_register %rbp
    movl    $0, -4(%rbp)
LBB0_1:                                 ## =>This Inner Loop Header: Depth=1
    jmp LBB0_1
    .cfi_endproc

and the do while loop

        .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp2:
    .cfi_def_cfa_offset 16
Ltmp3:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp4:
    .cfi_def_cfa_register %rbp
    movl    $0, -4(%rbp)
LBB0_1:                                 ## =>This Inner Loop Header: Depth=1
    jmp LBB0_2
LBB0_2:                                 ##   in Loop: Header=BB0_1 Depth=1
    movb    $1, %al
    testb   $1, %al
    jne LBB0_1
    jmp LBB0_3
LBB0_3:
    movl    $0, %eax
    popq    %rbp
    ret
    .cfi_endproc
Creepy answered 25/11, 2013 at 8:26 Comment(4)
+1 for the effort of actually investigating assembly codeJanes
On linux, I did gcc -S -o test1.asm testing.cpp with the three different loops in separate files, and did cmp test1.asm test2.asm, etc. There seems to be no difference.Hygroscope
+1 boredom creates useful stuff :)Wheelwright
unfortunately I'm not sufficiently familiar with assembly to know what all of that means. and @remyabel my gcc is version is Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) Target: x86_64-apple-darwin13.0.0 Thread model: posix out of curiosity, would u mind sharing ur version of gccCreepy
H
9

Everyone seems to like while (true):

https://mcmap.net/q/18776/-infinite-loops-top-or-bottom-closed

https://mcmap.net/q/18778/-which-is-the-correct-c-infinite-loop-for-or-while-true-closed

https://mcmap.net/q/18778/-which-is-the-correct-c-infinite-loop-for-or-while-true-closed

https://mcmap.net/q/18778/-which-is-the-correct-c-infinite-loop-for-or-while-true-closed

https://mcmap.net/q/18778/-which-is-the-correct-c-infinite-loop-for-or-while-true-closed

According to SLaks, they compile identically.

Ben Zotto also says it doesn't matter:

It's not faster. If you really care, compile with assembler output for your platform and look to see. It doesn't matter. This never matters. Write your infinite loops however you like.

In response to user1216838, here's my attempt to reproduce his results.

Here's my machine:

cat /etc/*-release
CentOS release 6.4 (Final)

gcc version:

Target: x86_64-unknown-linux-gnu
Thread model: posix
gcc version 4.8.2 (GCC)

And test files:

// testing.cpp
#include <iostream>

int main() {
    do { break; } while(1);
}

// testing2.cpp
#include <iostream>

int main() {
    while(1) { break; }
}

// testing3.cpp
#include <iostream>

int main() {
    while(true) { break; }
}

The commands:

gcc -S -o test1.asm testing.cpp
gcc -S -o test2.asm testing2.cpp
gcc -S -o test3.asm testing3.cpp

cmp test1.asm test2.asm

The only difference is the first line, aka the filename.

test1.asm test2.asm differ: byte 16, line 1

Output:

        .file   "testing2.cpp"
        .local  _ZStL8__ioinit
        .comm   _ZStL8__ioinit,1,1
        .text
        .globl  main
        .type   main, @function
main:
.LFB969:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        nop
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE969:
        .size   main, .-main
        .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB970:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jne     .L3
        cmpl    $65535, -8(%rbp)
        jne     .L3
        movl    $_ZStL8__ioinit, %edi
        call    _ZNSt8ios_base4InitC1Ev
        movl    $__dso_handle, %edx
        movl    $_ZStL8__ioinit, %esi
        movl    $_ZNSt8ios_base4InitD1Ev, %edi
        call    __cxa_atexit
.L3:
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE970:
        .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
        .type   _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB971:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $65535, %esi
        movl    $1, %edi
        call    _Z41__static_initialization_and_destruction_0ii
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE971:
        .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
        .section        .ctors,"aw",@progbits
        .align 8
        .quad   _GLOBAL__sub_I_main
        .hidden __dso_handle
        .ident  "GCC: (GNU) 4.8.2"
        .section        .note.GNU-stack,"",@progbits

With -O3, the output is considerably smaller of course, but still no difference.

Hygroscope answered 25/11, 2013 at 7:53 Comment(2)
I'm a heavily experienced developer, and I despise while (true).Disaffection
+1 for actually answering the question and showing how the compiler doesn't care what you use.Liggins
D
7

The idiom designed into the C language (and inherited into C++) for infinite looping is for(;;): the omission of a test form. The do/while and while loops do not have this special feature; their test expressions are mandatory.

for(;;) does not express "loop while some condition is true that happens to always be true". It expresses "loop endlessly". No superfluous condition is present.

Therefore, the for(;;) construct is the canonical endless loop. This is a fact.

All that is left to opinion is whether or not to write the canonical endless loop, or to choose something baroque which involves extra identifiers and constants, to build a superfluous expression.

Even if the test expression of while were optional, which it isn't, while(); would be strange. while what? By contrast, the answer to the question for what? is: why, ever---for ever! As a joke some programmers of days past have defined blank macros, so they could write for(ev;e;r);.

while(true) is superior to while(1) because at least it doesn't involve the kludge that 1 represents truth. However, while(true) didn't enter into C until C99. for(;;) exists in every version of C going back to the language described in the 1978 book K&R1, and in every dialect of C++, and even related languages. If you're coding in a code base written in C90, you have to define your own true for while (true).

while(true) reads badly. While what is true? We don't really want to see the identifier true in code, except when we are initializing boolean variables or assigning to them. true need not ever appear in conditional tests. Good coding style avoids cruft like this:

if (condition == true) ...

in favor of:

if (condition) ...

For this reason while (0 == 0) is superior to while (true): it uses an actual condition that tests something, which turns into a sentence: "loop while zero is equal to zero." We need a predicate to go nicely with "while"; the word "true" isn't a predicate, but the relational operator == is.

Disaffection answered 25/11, 2013 at 10:24 Comment(2)
I don't know; I think I prefer for(ever;and;ever); myself. Maybe it's a matter of personal preference. :)Janes
#define forever for(;;)Trifacial
E
5

They probably compile down to nearly the same machine code, so it is a matter of taste.

Personally, I would chose the one that is the clearest (i.e. very clear that it is supposed to be an infinite loop).

I would lean towards while(true){}.

Economic answered 25/11, 2013 at 7:26 Comment(0)
S
5

I use for(;/*ever*/;).

It is easy to read and it takes a bit longer to type (due to the shifts for the asterisks), indicating I should be really careful when using this type of loop. The green text that shows up in the conditional is also a pretty odd sight—another indication this construct is frowned upon unless absolutely necessary.

Sanbo answered 25/11, 2013 at 9:53 Comment(4)
Or just #define forever while(1). forever { ... }Statism
@Dmitry: You could do that, but that would defeat the point of instant readability. Someone else reading the code would have to look up the define to make sure forever is really a eternal loop. Adding the /*ever*/ adds just a bit extra readability.Sanbo
yes it is confusing at first but it has two benefits. First being that mouse over it in smart editors shows #define forever while(1), which should be clear to even beginners. Second is that it is overall more clear about the intent of the loop than the others. Not long ago, foreach loops were quite heretic and not obvious at first look, and now they are accepted as standard. Although personally I'd prefer "repeat" over "forever" since the loop does not actually loop forever, as it can be disrupted. To be fair beginners will see while(1) as confusing as repeat {}, if not more.Statism
Although I love "#define repeat for (;/*ever*/;)" the loss of standard syntax highlighting is probably not worth the macro and so I prefer the original version. Pity the language itself wont adopt "repeat/forever {"Rind
E
3

Is there a certain form which one should choose?

You can choose either. Its matter of choice. All are equivalent. while(1) {}/while(true){} is frequently used for infinite loop by programmers.

Extensity answered 25/11, 2013 at 7:25 Comment(0)
A
3

I would recommend while (1) { } or while (true) { }. It's what most programmers would write, and for readability reasons you should follow the common idioms.

(Ok, so there is an obvious "citation needed" for the claim about most programmers. But from the code I've seen, in C since 1984, I believe it is true.)

Any reasonable compiler would compile all of them to the same code, with an unconditional jump, but I wouldn't be surprised if there are some unreasonable compilers out there, for embedded or other specialized systems.

Adventurism answered 25/11, 2013 at 7:27 Comment(0)
R
2

Well, there is a lot of taste in this one. I think people from a C background are more likely to prefer for(;;), which reads as "forever". If its for work, do what the locals do, if its for yourself, do the one that you can most easily read.

But in my experience, do { } while (1); is almost never used.

Reinforce answered 25/11, 2013 at 7:34 Comment(0)
S
-5

All are going to perform same function, and it is true to choose what you prefer.. i might think "while(1) or while(true)" is good practice to use.

Sawyere answered 25/11, 2013 at 11:52 Comment(1)
-1: This answer doesn't anything meaningful to the question.Magbie
D
-6

They are the same. But I suggest "while(ture)" which has best representation.

Dependable answered 25/11, 2013 at 7:30 Comment(2)
-1: This answer doesn't anything meaningful to the question.Magbie
ture?? That won't compile!Hiltonhilum

© 2022 - 2024 — McMap. All rights reserved.