do {…} while (0) 作用的大致说法

/ 2评 / 0

经常看到别人的代码里面有这一行:

/**
  rief   Data Synchronization Barrier
  details Acts as a special kind of Data Memory Barrier.
           It completes when all explicit memory accesses before this instruction complete.
 */
#define __DSB() do {
                   __schedule_barrier();
                   __dsb(0xF);
                   __schedule_barrier();
                } while (0U)

这种宏的用途有什么好处?
Linux 的创始人是这么说的:

do{...}while(0)在C中是唯一的构造程序,让你定义的宏总是以相同的方式工作,这样不管怎么使用宏(尤其在没有用大括号包围调用宏的语句),宏后面的分号也是相同的效果.

那么不这样定义呢?比如:

#define foo(x) bar(x); baz(x)

然后你可能这样调用:

foo(wolf);

这将被宏扩展为:

bar(wolf); baz(wolf);

但是如下调用:

if (!feral)
    foo(wolf);

那么扩展后可能就不是你所期望的结果,上面语句将扩展为:

if (!feral)
    bar(wolf);
baz(wolf);

改进一下,试一下如此定义:

#define foo(x)  { bar(x); baz(x); }

那么上一个有问题的可就解决了吗?不是的,他展开是如此:

if (!feral) {
    bar(wolf);
    baz(wolf);
};
else
    bin(wolf);

如果是推荐定义中的呢,如下:

if (!feral)
    do { bar(wolf); baz(wolf); } while (0);

他等于:

if (!feral) {
    bar(wolf);
    baz(wolf);
}

展开是:

if (!feral)
    do
    {
        bar(wolf);
        baz(wolf);
    }
    while (0);
else
    bin(wolf);

这可能算是一种C语言陷阱.当然do{...}while(0)远远不止这个用途.比如说优化Goto语句,因为Goto语句不太容易读,而且容易出BUG,如下是Goto用法的片段.

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

他可以改成:

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

还有一种是定义空的宏定义,避免编译器在警告:

#define EMPTYMICRO do{}while(0)

可见,不仅仅可以做函数区块,还可以做各种其他用途,还是很好用的.

  1. myxiaonia说道:

    直接用一对{},两者有什么区别?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注