C provides several ways to iterate—repeat a sequence of steps. Chief among them are while
, do-while
and for
loops. Arduino adds the loop()
function for the main body of a program; canonically C does not provide that one on its own.
A while
loop resembles the following:
// Initialization can go here while (condition) { // Body of loop }
“condition
” is a placeholder—this gets replaced with some true/false statement; perhaps comparing a variable against a number, or checking the return status of another function. As long as the statement evaluates as true, then the code in the body of the loop is executed again and again.
Initializing one or more variables before the loop is common, but not required of all programs.
A do-while
loop moves the test condition to the end:
// Initialization can go here do { // Body of loop } while (condition);
“condition
”—the true/false statement—is evaluated after the body of the loop. So the loop always executes at least once.
Some logic just works better one way or the other.
A for
loop is sort of a contraction of the while
loop:
for (initialization; condition; operation) { // Body of loop }
“initialization
” is any code that sets up the loop…for example, it’s very common to set up a counter variable here. 92% of for
loops start with an “i=0
” initialization (programmer humor, not a true statistic, but it’s quite common).
“condition
” is just like the while
loop—a testable true/false statement, evaluated before each iteration of the loop. Very often tests a counter against some limit, e.g. i<10
.
“operation
” is a simple statement that’s performed after each iteration of the loop body. Very often used to increment a counter, e.g. i++
;
So three lines of code before now all fit into one. It’s a nice shorthand.
FUN FACT: conditional statements can also test integers for non-zero-ness. A variable with value 0
is equivalent to false
. 1
, 42
, -303
or any other non-zero integers are true
. Okay, maybe not fun, but it’s a fact.
Not often seen, hence occasional confusion, but any of the parts of a for
loop are optional; they can just be omitted when not needed, as long as the other remaining syntax (semicolons, etc.) is observed. These are all valid for
loops:
for (; condition; operation) { // Body of loop } for (initialization; ; operation) { // Body of loop } for (initialization; condition; ) { // Body of loop } for (initialization; condition; operation); // I ain't got no body
while
loops can also omit the body and just end with a semicolon, but do-while
loops always have the braces.
Recent C++ compilers allow declaring temporary variables right inside the initialization of a for
loop. This wasn’t always the case, so you don’t see it in older code. The “scope” of such variables is limited to the body of the loop (i.e. can’t be referenced after the loop).
One can also use a comma separator to pack more stuff into a line, e.g.
for (int a=0, b=1, c=2; a<10; a+=1, b+=2, c*=3) { Serial.printf("%d %d %d\n", a, b, c); }
(Note: Serial.printf()
is typically present only for 32-bit microcontrollers in Arduino. With Arduino UNO and other 8-bit devices, one must Serial.print()
each value separately.)
Old Habits Die Hard
It’s very common in C/C++/Arduino to structure an infinite loop (that is, repeats until power is cut) like the following:
while (1) { // Always true; repeats forever // Body of loop }
Occasionally there’s no body, if a program encounters an error and needs to “hang” because it can’t safely continue. The line just ends with a semicolon.
In the introduction, aged programmers, poor-quality compilers and code I wrote were all mentioned. Combined with a for
loop’s aforementioned optional elements, this yields a valid but little-seen infinite loop syntax:
for (;;) { // Body of loop }
I developed this habit because one particular compiler on one particular system decades ago would generate machine code that actually evaluates the truth of a while(1)
statement every time, instead of seeing the obvious infinite loop and simply jumping without evaluating. The empty for
was more efficient.
No compiler nowadays is that stupid, they will always do the right thing. But in the time and circumstances, it made programs a few cycles faster and a few bytes smaller.
I only stick with for(;;)
because it looks cool and I get to tell Big Iron Stories…but it’s preferable for teachable code to use while(1)
because that’s universally understood today as “infinite loop.”
Page last edited March 08, 2024
Text editor powered by tinymce.