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

1、避免goto语句:

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

 #defien N 

 bool Execute()
{
// 分配资源
int *p = (int *)malloc(N * sizeof(int));
bool bOk = true; // 执行并进行错误处理
bOk = func1();
if(!bOk)
{
free(p);
p = NULL;
return false;
} bOk = func2();
if(!bOk)
{
free(p);
p = NULL;
return false;
} bOk = func3();
if(!bOk)
{
free(p);
p = NULL;
return false;
} // .......... // 执行成功,释放资源并返回
free(p);
p = NULL;
return true;
}

C代码

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

 #defien N 

 bool Execute()
{
// 分配资源
int *p = (int *)malloc(N * sizeof(int));
bool bOk = true; // 执行并进行错误处理
bOk = func1();
if(!bOk) goto errorhandle; bOk = func2();
if(!bOk) goto errorhandle; bOk = func3();
if(!bOk) goto errorhandle; // .......... // 执行成功,释放资源并返回
free(p);
p = NULL;
return true; errorhandle:
free(p);
p = NULL;
return false;
}

C代码

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

 #defien N 

 bool Execute()
{
//分配资源
int *p = (int *)malloc(N * sizeof(int));
bool bOK = true; do {
//执行并进行错误处理
bOK = fun1();
if(!bOK) break; bOK = fun2();
if(!bOK) break; bOK = fun3();
if(!bOK) break; //.........
} while(); //释放资源 free(p);
p = NULL;
return bOK;
}

C代码

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

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

#define FOO do { } while(0)

3、提供一个声明局部变量的基础块:

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

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

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

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

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

if (x > y) {
int tmp;
tmp = x;
x = y;
y = tmp;
}
; // 空语句
else // ERROR!!!
do_something();

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

 if (x > y)
do {
int tmp;
tmp = x;
x = y;
y = tmp;
} while();
else
do_something();

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

 #define exch(x,y)       do {\
int tmp;\
tmp = x;\
x = y;\
y = tmp;\
} while()

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

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

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

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

if (blah == )
FOO(blah);

这将解释为:

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

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

if (blah == )
do {
printf("arg is %s\n", blah);
do_something_useful(blah);
} while ();

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

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

PS:以上的第三种和第四种技巧,并不是唯一的方法,有同学留言说用其他的方法也可以实现,反而显得这样的宏定义过于花哨?事实并非如此,这样的宏定义在linux内核代码中非常常见,原因是代码简洁、通用、可移植性好

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

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

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

  2. C语言中do...while(0)的妙用-避免goto

    使用goto的优雅并避免结构的混乱 将要跳转到的语句用do{-}while(0) 包起来就可以. reference #defien N 10 bool Execute() { // 分配资源 int ...

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

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

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

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

  5. C语言中do...while(0)用法小结

    在linux内核代码中,经常看到do...while(0)的宏,do...while(0)有很多作用,下面举出几个: 本文地址:http://www.cnblogs.com/archimedes/p/ ...

  6. 请问:c语言中d=1/3*3.0;与d=1.0/3*3;d=?有什么区别

    请问:c语言中d=1/33.0;与d=1.0/33;d=?有什么区别 d=1/33.0; 这时d=0,d=(1/3)3.0,这里1是整形,1/3也是整形,等于0,所以03.0=0 d=1.0/33; ...

  7. C语言中,头文件和源文件的关系(转)

    简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析阶段 3.编译阶段,首先编译成纯汇编语句, ...

  8. C 语言中 setjmp 和 longjmp

    在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处:但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转.后面我们会看到这两个函数在处理异常 ...

  9. C语言中qsort函数用法

    C语言中qsort函数用法-示例分析    本文实例汇总介绍了C语言中qsort函数用法,包括针对各种数据类型参数的排序,非常具有实用价值非常具有实用价值. 分享给大家供大家参考.C语言中的qsort ...

随机推荐

  1. MATLAB命令大全

    一.常用对象操作:除了一般windows窗口的常用功能键外.1.!dir 可以查看当前工作目录的文件. !dir& 可以在dos状态下查看.2.who 可以查看当前工作空间变量名, whos ...

  2. BZOJ 4516: [Sdoi2016]生成魔咒

    Description 给出一串数字,求每次插入一个数字后本质不同的子串. Sol SAM. 在 SAM 上添加节点的时候统计一下 \(val[np]-val[par[np]]\) 就可以了... 用 ...

  3. Visual Studio与Chrome调试工具使用技巧

    VS: 1: Ctrl + Enter (在光标指定位置的上面添加一行,并将光标移至新添加行的行首位置) Ctrl + Shift + Enter (在光标指定位置的下面添加一行,并将光标移至新添加行 ...

  4. C#之this的使用

    msdn地址: https://msdn.microsoft.com/zh-cn/library/bb383977(v=vs.120).aspx 扩展方法使你能够向现有类型“添加”方法,而无需创建新的 ...

  5. Effective C++ -----条款30:透彻了解inlining的里里外外

    将大多数inlining限制在小型.被频繁调用的函数身上.这可使日后的调试过程和二进制升级(binary upgradability)更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化 ...

  6. log4net使用

    平时项目里一直都有在使用log4net作为日志记录模块,当时一直都没有去理解log4net的配置文件信息.今天抽出了一点时间来看了看配置文件信息. log4net配置文件信息: <log4net ...

  7. 如何让两个 并列的div高度相等

    哪个div Height值大,就将其值赋给Height值小的div,从而使2个div高度始终保持一致. function $(id){ return document.getElementById(i ...

  8. 创建URL为空的解决办法

    在使用+URLWithString:或-initWithString:创建一个URL对象时,提供的参数字符串必须符合RFC 2396标准(O网页链接.而这两个方法又是根据RFC 1738(O网页链接和 ...

  9. 解决Eclipse里Maven工程报 An error occurred while filtering resources错误

    这几天被maven的单元测试折腾死了,以为是自己的eclipse有问题呢,今天早上来了又发现eclipse报了一个很奇怪的错误:An error occurred while filtering re ...

  10. Android笔记:实现点击事件

    布局文件声明控件 .java文件获取控件 1. button.setOnClickListener(new View.OnClickListener() {            @Override  ...