Tuesday, September 26, 2006

While(0) - Does it make sense?!

Generally, as a programmer we have used while(1) in many places. For example,

while(1)
{
...

if (condition == true)
break;
...
}

This is an infinite loop and we break the loop explicitly when some condition is met.

But what is the use of while(0)?! In while(0), the conditon is always false, so the loop won't be executed even once. So, at first glance, we all would think, this is such a dumb statement. Here is an interesting case where I found while(0) very useful. This cameup when I was discussing with my friend sometime back.

Consider the following example,

int fun()
{
File *fp = fopen(...);
//do something here
if (condition1= true)
Goto Label;

//do something here
if (condition2= true)
Goto Label;


//do something here
if (condition2= true)
Goto Label;

Label:
fclose(fp);
return 1;
}

In the above code, there are multiple return paths but all should return only after closing the file. So, we cannot avoid labels here. One way to avoid lablels is to use while(0).

int fun()
{
File *fp = fopen(...);

do
{
//do something here
if (condition1= true)
break;

//do something here
if (condition2= true)
break;

//do something here
if (condition3= true)
break;

} while(0);

fclose(fp);
return 1;
}

Ain't this elegant? Atleast I liked this style.

6 comments:

Sunil said...

I had come across another place where they used this construct.

#define SOME_MACRO(A,B) do{//multiple lines of code}while(0)

Guess why?

kart said...

Good!! I guess, it is to detect macro errors.
'Do' should always have a corresponding while. Otherwise, compiler will throw an error. So, if macro doesn't replace all the enclosed lines (bcoz of some typos), then the compiler will throw error.

Compile time errors are always better than run time error!!

Sunil said...

Oh come on, the preprocessor would always expand the macro. :) Also if you want the enitr code segment inside a block you could go for

#define SOME_MACRO(A,B) {//multiple lines of code}

Why a do, while(0)

kart said...

Oh... I remember, we discussed this with Venky sometime in our old house.

As you said, a simple bracket would solve the problem below only when there is no semicolon after the macro.

# define MACRO {int i;int j;}
# define MACRO2 do{int i;int j;}while(0)

if condition1
MACRO;
else if condition2
MACRO2;
else
break;
would expand as

if condition1
{int i;int j;}; //since comma is a new line, we will get an erro

elseif condition2
do{int i;int j;}; //single line...

else
break;

Venkatesan Sharma said...

The title should be modified as do..while(0). while and do..while are totally different beasts. The do..while(0) is basically to give the macro same usage syntax as a fn.

Eg:

int i,j;

fooFn(i,j);
fooMac(i,j)

printf(some shit);

here, as you see the macro seems a bit odd without a semicolon. if you put a semicolon here, it doesnt matter, but in the case you quoted, it does pose a problem as there is some spurious statement before else which is an error.

Dynish said...

wonder why you wouldnt do this?
int fun()
{
File *fp = fopen(...);

if (condition1= true)
fun();
if (condition2= true)
fun();
if (condition3= true)
fun();
fclose(fp);
return 1;
}