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

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

有以下几点原因:

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

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

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

#define FOO(x) \

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

do_something_useful(x);

如果这样用:

if (blah == 2)

F00(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();

  问题是由于在语句块后直接加入分号(;)引起的. 解决办法是将语句块放入 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

【转】linux中do{...} while(0)的解释的更多相关文章

  1. linux中shell变量$#,$@,$0,$1,$2的含义解释

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  2. linux中shell变量$#,$@,$0,$1,$2的含义解释

    linux中shell变量$#,$@,$0,$1,$2的含义解释 linux中shell变量$#,$@,$0,$1,$2的含义解释:  变量说明:  $$  Shell本身的PID(ProcessID ...

  3. 【转】linux中shell变量$#,$@,$0,$1,$2的含义解释

    原文网址:http://www.cnblogs.com/fhefh/archive/2011/04/15/2017613.html linux中shell变量$#,$@,$0,$1,$2的含义解释: ...

  4. 【Shell】linux中shell变量$#,$@,$0,$1,$2的含义解释 && set 关键字使用

    linux中shell变量$#,$@,$0,$1,$2的含义解释   摘抄自:ABS_GUIDE 下载地址:http://www.tldp.org/LDP/abs/abs-guide.pdf linu ...

  5. 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释

    浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...

  6. linux中shell变量$#,$@,$0,$1,$2的含义

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  7. linux中shell变量$#,$@,$0,$1,$2

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  8. Linux中shell变量$0,$?等含义

    linux中shell变量$#,$@,$0,$1,$2的基本含义: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  9. linux中shell变量$#,$@,$0,$1,$2的含义解释<转>

    linux中shell变量$#,$@,$,$,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行的命 ...

随机推荐

  1. zTree Jquery eCharts

    (function(){ var setting = { view:{ dblClickExpand:false, expandSpeed:300 }, data: { simpleData: { e ...

  2. iOS当中一些常见的面试题

    转自各方面..... 一.前言部分 文中的问题多收集整理自网络,不保证100%准确,还望斟酌采纳. 1.iOS9有哪些新特性? 答案: 1)改进了 Siri 基于日期.位置和相簿名称来搜索个人照片和视 ...

  3. java 文件上传

    java 上传文件  如果不依赖框架的话  要利用 Apache 中几个jar文件来处理   1.  给表单设置enctype属性,其值为 "multipart/form-data" ...

  4. AngularJs自定义指令--执行顺序 (原文:http://www.cnblogs.com/sagacite/p/4624227.html)

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. 【数论】X problem

    X problem      X问题     Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...

  6. DataTable与实体类互相转换

    /// <summary> /// DataTable与实体类互相转换 /// </summary> /// <typeparam name="T"& ...

  7. C++11特性(模板类 initializer_list)

    [1]initializer_list模板类 C++primer 原文如下: 通读原文相关篇幅,分析解读内容如下: 提供initializer_list类的初衷,为了便于将有限个同一类型(或可转换为同 ...

  8. catalina

    用catalina启动tomcat容器,将项目放到tomcat中,通过cmd:启动:catalina,相当于本地的测试环境.

  9. 使用httpclient发送http请求

    先来个httpclient的maven依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> &l ...

  10. JDStatusBarNotification和一些宏定义

    // //  AddTopicViewController.m //  vMeet2 // //  Created by 张源海 on 16/6/30. //  Copyright © 2016年 h ...