Why I don’t “while”

I don’t “while”.  I don’t use the C “while” command to build loops.  I also don’t “do while”.  I think you shouldn’t either.

Years ago I was responsible for maintaining a custom embedded tasking system which executed on an industrial controller.  I did not write the original code, but I had been fixing it and adding more features to it for several years; a claim could be made that I had written over half of the now existing operating code. So it is possible I created the problem.

The problem was that the task system would hang every once in a while.  It did not do this very often, but it was often enough over the hundreds of controllers operated by one customer that they were getting annoyed.  I set-up a real-time test system, forced it to mimic the problem and began the process of debugging.  I tracked the problem down to a loop that was waiting for the transmit-complete flag to be set by the UART.

Hardware UART transmit is very simple.  The code writes the character to the transmit register.  After this the hardware moves the character to the shift register, the character starts to transmit and after the start bit, 8 data bits and one stop bit are shifted out of the UART, the hardware then sets the transmit-complete flag.  How could the code stay trapped in the loop forever?

Can’t fail.  But it did fail.  It turns out that fixes, upgrades and re-partitioning of the code had created a very unique, seldom used code path that would try to send the character when the UART was disabled.  Oops.  The task system hung because the “while” loop waited on a transmit-completed flag that never set.  (I’ll not discuss Watchdog timers here; the system had a watchdog timer and that made the situation worse.)

Lesson learned.  If you want to write code that works, ALWAYS WORKS, you should write loops that terminate after a maximum number of cycles.  Using the “for” command, the code looks like…

for( cntDn = CONST_MAXLOOPS; cntDn > 0; cntDn -= 1)

I prefer the count variable to decrement to zero, but it’s OK if you prefer to count up.  With this loop, I know the maximum loop time.  To this command, we can add a flag variable…

for( cntDn = CONST_MAXLOOPS; (flag != true) && (cntDn > 0); cntDn -= 1)

This loop always terminates.  (This assumes ‘cntDn’ is not changed within the loop; changing the counting variable in the loop is not a good coding practice.)

For those that need to know if the loop completed by counting or by the flag, simply check the flag one last time after the loop completes.  If the flag is still not set, the loop must have timed-out.  Now the code can be written to handle the timeout.

Can the same result be achieved with a “while” command.  Of course, but the “for” command provides the additional benefit of initializing, testing and incrementing the loop control variables in one place.  This is one of the reasons the MISRA standards committee prefers the “for loop”. 

A little extra effort when writing the code can yield large benefits when testing and verifying the code for proper operation.  (To complete the story, I did modify the code so the UART hardware was always enabled before transmitting, but from then on, I always wrote loops that terminated in a maximum number of counts.)

In full disclosure I use “while” in one circumstance.  I write “while( 1)” for loops that run forever.