Forgot do in do... while loop

Why does this still compile and run?

It doesn't because status is not defined.

It seems to me that the compiler should reject this as nonsensical or at least raise a warning (I have -Wall in my compiler options).

Assuming you define status, it is a valid program. Some compilers or analyzers may generate warnings for infinite loops or for no-op while bodies.


The compiler cannot raise an error here since according to section 6.5 of the C++11 standard this is perfectly valid code. In fact there are two flavors of while:

  1. while ( condition ) statement
  2. do statement while ( expression );

statement can be

  • a single statement or
  • a block of statements in curly braces or
  • the empty statement (;)

With this in mind let me format your code how the compiler sees it:

int main () {
  int status;

  { // braced block that just creates a new scope
    status = foo();
  }

  while (status) /* empty statement */;
}

While it might be obvious to a human reader that you meant to loop over the code in curly braces this isn't obvious to the compiler. This has to do with the fact that C++ compilers generally don't look at indentation and line-breaks. An analysis tool taking them into account could warn you that the way you formatted your code doesn't go together with what it is actually doing and correct that for you. That would make the mistake more obvious to you. Or maybe one day we get a language feature which allows us to say explicitly "empty statement". This would allow us to clearly state our intent. Once we have that compilers could issue a warning when the code isn't clear. Until then we have to be careful - C++ is a powerful language but it has a few sharp edges...

BTW you're not the first one who drew wrong conclusions from indentation/line-breaks.


I'm assuming you actually had int status outside of the loop body, otherwise the code wouldn't compile. (Not even with the do in place.)

With that fixed, the code you wrote is still valid without do, but does something differrent, as you already correctly noted. Let me rewrite it slightly to show how it is interpreted:

int main () {
  int status;

  { // anonymous braced block that just creates a new scope
    status = foo();
  }

  while (status) {
    // empty loop body
  }
}

A stand-alone block like that does have its uses, for example to utilize RAII - it could contain a local variable with an object whose destructor frees some resource when it goes out of scope (for example a file handle), among other things.

The reason that the while (status); is the same as while (status) {} is because you are allowed to put either a single statement or a block, and ; is a valid statement that does nothing.

And writing something like while (someVariable); isn't even nonsensical in general (although of course in this case it is) because it is essentially a spinlock, a form of busy waiting - it would leave the loop if another processor core, some I/O component or an interrupt would modify the value of someVariable so that the condition is no longer fulfilled, and it would do so without any delay. You would probably not write such code on a desktop platform where "hogging CPU" is a bad thing (except in specific scenarios in kernel-mode code), but on an embedded device like a microcontroller (where your code is the only code that runs) it can be a perfectly valid way of implementing code that waits for some external change. As pointed out by Acorn in the comments, this would of course only make sense if someVariable were volatile (or otherwise non-predictable), but I'm talking about busy loops on a variable in general.

Tags:

C++