Chinaunix首页 | 论坛 | 博客
  • 博客访问: 824902
  • 博文数量: 92
  • 博客积分: 1498
  • 博客等级: 上尉
  • 技术积分: 993
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-18 18:31
文章分类

全部博文(92)

文章存档

2013年(2)

2012年(3)

2011年(3)

2010年(61)

2009年(23)

分类: LINUX

2010-12-16 20:39:34

在linux内核源码中,经常会碰到这样的结构do{} while(0)这样的语句,细心的人也会发现,这样的用法常常是在宏中使用,当然,初次见到的时候,和大多数人的想法是一样的,这不没有意义么,还是将do包含的代码执行一遍,当然,能这样写肯定有它的特殊作用么:
 
这里有个简单的宏来测试这个功能:(这个演示参考网上的一段代码)
#define SAFE_FREE(p) do { free(p); p = NULL; } while(0)
如果这里去掉do...while(0),定义SAFE_FREE为:
#define SAFE_FREE(p) free(p); p = NULL;

那么以下代码:
if (NULL != p)
   SAFE_FREE(p)
else
  ...

会被展开为:
if (NULL != p)
  free(p); p = NULL;
else
  ...

展开的代码中存在两个问题:
  • if 分支后面有两个语句,导致else分支没有对应的if,编译失败;
  • 假设没有else分支,则SAFE_FREE中的第二个语句无论if测试是否通过都会执行。

将SAFE_FREE的定义加上{}就可以解决上诉问题了,即:
#define SAFE_FREE(p) { free(p); p = NULL; }

这样,代码:
if (NULL != p)
   SAFE_FREE(p)
else
  ...

会被展开为:
if (NULL != p)
  { free(p); p = NULL; }
else
  ...

但是,在C程序中,每个语句后面加分号是一种约定俗成的习惯,那么,如下代码:
if (NULL != p)
   SAFE_FREE(p)
else
  ...

将为扩展为:
if (NULL != p)
  { free(p); p = NULL; };
else
  ...

这样,else分支就有没有对应的if了,编译将无法通过。假设用了do{}while(0),情况就不一样那个了,同样的代码会被扩展为:
if (NULL != p)
  do { free(p); p = NULL; } while(0);
else
  ...

不会再出现编译问题。do{}while(0)的使用完全是为了保证宏定义的使用者能无编译出错的使用宏。
阅读(1281) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~