在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)的使用完全是为了保证宏定义的使用者能无编译出错的使用宏。
阅读(1274) | 评论(0) | 转发(0) |