1

do{...}while(0)的意义和用法

 2 years ago
source link: https://blogread.cn/it/article/5907?f=hot1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

do{...}while(0)的意义和用法

浏览:4412次  出处信息

    linux内核和其他一些开源的代码中,经常会遇到这样的代码:

do{
 ...
}while(0)

    这样的代码一看就不是一个循环,do..while表面上在这里一点意义都没有,那么为什么要这么用呢?

    实际上,do{...}while(0)的作用远大于美化你的代码。查了些资料,总结起来这样写主要有以下几点好处:

    1、辅助定义复杂的宏,避免引用的时候出错:

    举例来说,假设你需要定义这样一个宏:

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

    这个宏的本意是,当调用DOSOMETHING()时,函数foo1()和foo2()都会被调用。但是如果你在调用的时候这么写:

if(a>0)
    DOSOMETHING();

    因为宏在预处理的时候会直接被展开,你实际上写的代码是这个样子的:

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

    这就出现了问题,因为无论a是否大于0,foo2()都会被执行,导致程序出错。

    那么仅仅使用{}将foo1()和foo2()包起来行么?

    我们在写代码的时候都习惯在语句右面加上分号,如果在宏中使用{},代码里就相当于这样写了:“{...};”,展开后就是这个样子:

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

    这样甚至不会编译通过。所以,很多人才采用了do{...}while(0);

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

    这样,宏被展开后,才会保留初始的语义。GCC提供了Statement-Expressions用以替代do{...}while(0); 所以你也可以这样定义宏:

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

    http://www.spongeliu.com/

     2、避免使用goto对程序流进行统一的控制:

    有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:

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

    由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理:

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

    这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。

    3、避免空宏引起的warning

    内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:

#define EMPTYMICRO do{}while(0)

    4、定义一个单独的函数块来实现复杂的操作:

    当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);,将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。

QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK