在linux内核代码中,经常看到do...while(0)的宏,do...while(0)有很多作用,下面举出几个:

本文地址:http://www.cnblogs.com/archimedes/p/do-while-0.html,转载请注明源地址。

1、避免goto语句:

通常,如果一个函数开始要分配一些资源,然后如果在中途遇到错误则要退出函数,当然,退出前要释放资源,我们的代码可能如下: 

  1. #defien N
  2.  
  3. bool Execute()
  4. {
  5. // 分配资源
  6. int *p = (int *)malloc(N * sizeof(int));
  7. bool bOk = true;
  8.  
  9. // 执行并进行错误处理
  10. bOk = func1();
  11. if(!bOk)
  12. {
  13. free(p);
  14. p = NULL;
  15. return false;
  16. }
  17.  
  18. bOk = func2();
  19. if(!bOk)
  20. {
  21. free(p);
  22. p = NULL;
  23. return false;
  24. }
  25.  
  26. bOk = func3();
  27. if(!bOk)
  28. {
  29. free(p);
  30. p = NULL;
  31. return false;
  32. }
  33.  
  34. // ..........
  35.  
  36. // 执行成功,释放资源并返回
  37. free(p);
  38. p = NULL;
  39. return true;
  40. }

这里最大的问题是代码冗余,每增加一个操作,就要做相应的错误处理,非常不灵活,于是想到了一下的goto:

  1. #defien N
  2.  
  3. bool Execute()
  4. {
  5. // 分配资源
  6. int *p = (int *)malloc(N * sizeof(int));
  7. bool bOk = true;
  8.  
  9. // 执行并进行错误处理
  10. bOk = func1();
  11. if(!bOk) goto errorhandle;
  12.  
  13. bOk = func2();
  14. if(!bOk) goto errorhandle;
  15.  
  16. bOk = func3();
  17. if(!bOk) goto errorhandle;
  18.  
  19. // ..........
  20.  
  21. // 执行成功,释放资源并返回
  22. free(p);
  23. p = NULL;
  24. return true;
  25.  
  26. errorhandle:
  27. free(p);
  28. p = NULL;
  29. return false;
  30. }

代码冗余是解决了,但是引入了C语言中比较微妙的goto语句,虽然正确的使用goto语句可以大大提高程序的灵活性与简洁性,但是会使我们的程序捉摸不定,为了既避免使用goto语句,又能消除代码冗余,可以考虑使用下面的 do...while(0):

  1. #defien N
  2.  
  3. bool Execute()
  4. {
  5. //分配资源
  6. int *p = (int *)malloc(N * sizeof(int));
  7. bool bOK = true;
  8.  
  9. do {
  10. //执行并进行错误处理
  11. bOK = fun1();
  12. if(!bOK) break;
  13.  
  14. bOK = fun2();
  15. if(!bOK) break;
  16.  
  17. bOK = fun3();
  18. if(!bOK) break;
  19.  
  20. //.........
  21. } while();
  22.  
  23. //释放资源
  24.  
  25. free(p);
  26. p = NULL;
  27. return bOK;
  28. }

2、避免空声明在编译时出现警告:

在linux内核源代码中,经常看到如下宏以避免在编译时出现警告:

  1. #define FOO do { } while(0)

3、编写符合习惯的代码块:

你可能经常会使用如下的宏:

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

然而在某些情况下将会失效,下面的代码使用if...else...

  1. if (x > y)
  2. exch(x,y); // 分支 1
  3. else
  4. do_something(); // 分支 2

但是将被解释为一个分支的if语句:

  1. if (x > y) {
  2. int tmp;
  3. tmp = x;
  4. x = y;
  5. y = tmp;
  6. }
  7. ; // 空语句
  8. else // ERROR!!!
  9. do_something();

错误出在“;”直接位于代码块的后面,解决的办法是将代码嵌入do...while(0),于是得到下面的代码:

  1. if (x > y)
  2. do {
  3. int tmp;
  4. tmp = x;
  5. x = y;
  6. y = tmp;
  7. } while();
  8. else
  9. do_something();

于是上面的宏可以修改为:

  1. #define exch(x,y) do {\
  2. int tmp;\
  3. tmp = x;\
  4. x = y;\
  5. y = tmp;\
  6. } while()

4、在条件语句中使用复杂的宏:

假如一个宏包含类似如下几行代码:

  1. #define FOO(x) \
  2. printf("arg is %s\n", x); \
  3. do_something_useful(x);

现在想像一下下面的代码:

  1. if (blah == )
  2. FOO(blah);

这将解释为:

  1. if (blah == )
  2. printf("arg is %s\n", blah);
  3. do_something_useful(blah);;

我们就会发现,if语句只作用于printf(), do_something_useful() 没按照愿意一起执行,即没有像你预期的那样被包含在if代码中,于是可以使用如下的代码块:

  1. if (blah == )
  2. do {
  3. printf("arg is %s\n", blah);
  4. do_something_useful(blah);
  5. } while ();

这样上面的宏就可以改为:

  1. #define FOO(x) do { \
  2. printf("arg is %s\n", blah);\
  3. do_something_useful(blah);\
  4. } while ()

C语言中do...while(0)用法小结的更多相关文章

  1. C语言中system()函数的用法总结(转)

    system()函数功能强大,很多人用却对它的原理知之甚少先看linux版system函数的源码: #include <sys/types.h> #include <sys/wait ...

  2. C语言中do...while(0)的妙用(转载)

    转载来自:C语言中do...while(0)的妙用,感谢分享. 在linux内核代码中,经常看到do...while(0)的宏,do...while(0)有很多作用,下面举出几个: 1.避免goto语 ...

  3. C/C++语言中NULL、'\0’和0的区别

    注:本文参考了http://blog.csdn.net/mylinx/article/details/6873253及书籍<征服C指针>([日]前桥和弥著). NULL.'\0'和0的值是 ...

  4. C语言中static关键字的用法

    C记得还是大一时学的,现在觉得好久没用了,又捧起来看看.今天刚看到有关static关键字,仔细地看了一遍<C和指针>这本书中的解释,现在觉得清楚多了. 首先,我们将static关键字,修饰 ...

  5. C语言中的extern关键字用法

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”. 1. extern修饰变量的声明.举例来说,如果文件a.c需要引用b.c中变量int v ...

  6. C语言中sprintf()函数的用法

    sprintf函数的用法 1.该函数包含在stdio.h的头文件中. 2.sprintf和平时我们常用的printf函数的功能很相似.sprintf函数打印到字符串中,而printf函数打印输出到屏幕 ...

  7. C语言中strtod()函数的用法详解

    函数原型: #include <stdlib.h> double strtod(const char *nptr, char **endptr); C语言及C++中的重要函数. 名称含义 ...

  8. R语言中的logical(0)和numeric(0)以及赋值问题

    logical(0) 不等于 numeric(0).两者都不等于NULL值,即is.null(logical(0))和is.null(numeric(0))返还值都是FALSE.这很有意思,说明长度为 ...

  9. C语言中do...while(0)的妙用

    在linux内核代码中,经常看到do...while(0)的宏,do...while(0)有很多作用,下面举出几个: 1.避免goto语句: 通常,如果一个函数开始要分配一些资源,然后如果在中途遇到错 ...

随机推荐

  1. 析构函数和Dispose的使用区别

    老生常谈的问题了,MSDN也有非常详细的说明但看起来不是很系统.也曾经做过分析,但没有总结下来又忘了,这次整理一下MSDN和网上搜集的一些资料,以备不时只需. 下面是MSDN对这两个函数的建议使用方法 ...

  2. Mina、Netty、Twisted一起学(四):定制自己的协议

    在前面的博文中,介绍一些消息分割的方案,以及MINA.Netty.Twisted针对这些方案提供的相关API.例如MINA的TextLineCodecFactory.PrefixedStringCod ...

  3. Xcode-打开代码折叠带

    preferences --> Text Editing --> 打勾Code folding ribbon

  4. DirectWrite文字排版——字符串去尾

    DirectWrite是 DirectX 家族中专门用来做文本处理的部分,主要配合Direct2D进行渲染工作. 一.字符串去尾介绍 在文字渲染中,不免会遇到字符串去尾的需求.字符串去尾指的是:当字符 ...

  5. ASP.NET MVC 5 默认模板的JS和CSS 是怎么加载的?

    当创建一个默认的mvc模板后,项目如下: 运行项目后,鼠标右键查看源码,在源码里看到头部和尾部都有js和css文件被引用,他们是怎么被添加进来的呢? 首先我们先看对应的view文件index.csht ...

  6. [Architect] Abp 框架原理解析(4) Validation

    本节目录 介绍 DataAnnotations ICustomValidate IShouldNormalize 实现Abp Validation 介绍 Abp中在Application层集成了val ...

  7. 树莓派配置静态ip

    #vim /etc/network/interfaces 修改为如下内容: auto eth0 iface eth0 inet static address 192.168.0.2 netmask 2 ...

  8. SQLDMOHelper

    在网上传闻SQLDMO是个好东西,当时没有注意这个传闻是什么时候了,后来才在微软的官网上看见,从SQL Server2008开始就不用SQLDMO了,取而代之的是SMO.无奈了,还写了个Helper. ...

  9. 新的Visual C++代码优化器

    微软在 5 月 4 日发布了新的高级代码优化器,服务于 Visual C++ 的后端编译器.提高了代码性能,可以压缩代码体积,将编译器带入了一个新的境界. Visual C++ 的团队在博客上称,这将 ...

  10. margin的使用方法与技巧

    1.margin还可以用来做平移,作用类似translate哈哈.将元素设成absolute后就可以用margin随便平移他了,既不像relative那样要霸占空间,又不用为父元素设置relative ...