Significance and use of do{...}while(0)

  sonic0002        2012-10-21 21:13:22       10,625        0    

In some Linux kernel and other open source codes, we can see some codes like below:

do{
 ...
}while(0)

This code snippet is not a loop, it seems there is no significance of using do...while this way, then why should we use it?

In fact, the significance of do{...}while(0) is better than optimizing your code. After some research, we summarize some benefits of it.

1. Help define complex macro to avoid error

#define DOSOMETHING()\
               foo1();\
               foo2();

The meaning of the macro is when calling DOSOMETHING(), the functions foo1() and foo2() will be called. But if you write it like this when calling

if(a>0)
    DOSOMETHING();

Since macro will be expanded directly when preprocessing, the actual code will like this:

if(a>0)
    foo1();
foo2();

This introduces the problem, because no matter whether a is larger than b, foo2() will be called.

Then can we use {} to include foo1() and foo2()? We are used to write semicolon at the end of a statement, so if we use {} in a macro, the code will be like :

if(a>0)
{
    foo1();
    foo2();
};

This code will not be compiled. So many people use do{...}while(0)

#define DOSOMETHING() \
        do{ \
          foo1();\
          foo2();\
        }while(0)\
    
...
 
if(a>0)
    DOSOMETHING();
 
...

When the macro is expanded, the original meaning will remain. GCC provides Statement-Expression to replace do{...}while(0), we can define macro as below:

#define DOSOMETHING() ({\
        foo1(); \
        foo2(); \
})

2. Avoid using goto to control program workflow

In some functions, we may do some work before calling the return statement, for example free some memory allocated using malloc at the beginning of the function. goto is always a simple method:

int foo()
{
    somestruct* ptr = malloc(...);
 
    dosomething...;
    if(error)
    {
        goto END;
    }
 
    dosomething...;
    if(error)
    {
        goto END;
    }
    dosomething...;
 
END:
    free(ptr);
    return 0;
 
}

Since goto may make the code difficult to read, many people don't recommend to use it, then we can use do{...}while(0)

int foo()
{
 
    somestruct* ptr = malloc(...);
 
    do{
        dosomething...;
        if(error)
        {
            break;
        }
 
        dosomething...;
        if(error)
        {
            break;
        }
        dosomething...;
    }while(0);
 
    free(ptr);
    return 0;
 
}

 

Here we use do{...}while(0) to include the main body of the function and use break to replace goto.

3. Avoid warning caused by macro

Due to constraint of different architectures of kernel, we may use empty macro many times, when compiling, the empty macro will produce warning, to avoid this kind of warning, we can use do{...}while(0) to define empty macro.

#define EMPTYMICRO do{}while(0)

4. Define a single function block to complete complex operations

If you have a complex function and you don't want to create a new function, by using do{...}while(0), you can put some codes there and define some variables so that you no need to worry about whether the variable names outside of do{...}while(0) are the same as the variable names inside so{...}while(0)

If you find any other good use of do{...}while(0), you can share with us.

Source : http://www.spongeliu.com/415.html

DO{...}WHILE(0)  OPTIMIZATION 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

I can do it