2007年4月20日星期五

Linux内核源码中的do while(0)

为什么在内核中碰到很多 #defines ... do{ ... } while(0)?

有以下几点原因:

  • 空语句在编译时候会出现警告,所以有必要用#define FOO do { } while(0).

  • 这样做是为了能够在里面定义局部变量

  • 这样做是为了能够在条件语句中使用复杂的宏定义. 例如下面这段代码:

    #define FOO(x) \
    printf("arg is %s\n", x); \
    do_something_useful(x);
    如果这样用:
    if (blah == 2)
    FOO(blah);
    将会被展开为:
    if (blah == 2)
    printf("arg is %s\n", blah);
    do_something_useful(blah);;

    这样,if条件之包含了printf()语句,而 do_something_useful()调用不能按期望那样工作。而使用 do { ... } while(0)定义后,就会展开成以下语句:

    if (blah == 2)
    do {
    printf("arg is %s\n", blah);
    do_something_useful(blah);
    } while (0);
    这是所期望的状况.
  • 如果你希望定义一个包含多行语句和一些局部变量的时候. 一般的定义方式只能这样:

    #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

    然而在某些情况下,这样并不能正常工作. 下面是包含两个分支的if语句:

    if (x > y)
    exch(x,y); // Branch 1
    else
    do_something(); // Branch 2

    但这样却只能展开成单分支的if语句,如下:

    if (x > y) {                // 单分支if
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
    }
    ; // 空语句
    else // 错误!!! "parse error before else"
    do_something();

    问题是由于在语句块后直接加入分号(;)引起的. 解决办法是将语句块放入 dowhile (0)中间.这样就得到了一条单语句, 而不是被编译器判断为语句块.现在的if语句如下:

    if (x > y)
    do {
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
    } while(0);
    else
    do_something();

没有评论: