zoukankan      html  css  js  c++  java
  • 【转】linux中do{...} while(0)的解释

      在看ldlm的代码过程中遇到了一个很奇怪的问题,有很多宏定义使用了do while(0)这种看起来好像没啥用的代码。然后我就问问师兄,才得知,这种用法很常见,自己又查了一下资料,原来在linux内核代码中经常用到这个东西!现在就将这个东西整理一下。

            

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

    有以下几点原因:

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

    2、给定一个基本块,可以在里面定义局部变量

    3、为了能够在条件语句中使用复杂的宏定义。例如下面这段代码:

         #define FOO(x)

         printf("arg is %s ", x);

         do_something_useful(x);

          如果这样用:

          if (blah == 2)

              F00(blah);

          将会被展开为:

          if (blah == 2)

                  printf("arg is %s ", blah);

                  do_something_useful(blah);

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

    if (blah == 2)

    do{

                  printf("arg is %s ", 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();

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

      if (x > y)

      do {

      int tmp;

      tmp = x;

      x = y;

      y = tmp;

      } while(0);

      else

      do_something();

    假设有这样一个宏定义  
     
    #define  macro(condition)  if(condition)  dosomething();  
     
    现在在程序中这样使用这个宏:  

    if(temp)  
                 macro(i);  
    else  
                 doanotherthing();  
     
    一切看起来很正常,但是仔细想想。这个宏会展开成:  
     
    if(temp)  
                 if(condition)  dosomething();  
    else    
                 doanotherthing();  
     
    这时的else不是与第一个if语句匹配,而是错误的与第二个if语句进行了匹配,编译通过了,但是运行的结果一定是错误的。  
     
    为了避免这个错误,我们使用do{….}while(0)  把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。  

     

    参考资料

    http://blog.csdn.net/chenhu_doc/article/details/856468

    http://www.233.com/linux/fudao/20101102/140715235.html

  • 相关阅读:
    尬聊攻略丨过年回家,你最怕被亲戚问什么?
    有人被盗刷900次? 支付宝发布年终“神反转”盘点
    470余万条疑似12306用户数据遭贩卖 嫌疑人被刑拘
    利用Python实现对Web服务器的目录探测
    栈空间溢出
    KB奇遇记(6):搞笑的ERP项目团队
    探寻不同版本号的SDK对iOS程序的影响
    阅读《Android 从入门到精通》(24)——切换图片
    leetcode
    Grunt的配置及使用(压缩合并js/css)
  • 原文地址:https://www.cnblogs.com/Lyush/p/3504559.html
Copyright © 2011-2022 走看看