define do{} while(0) 用法妙用

没有检索到摘要

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

define do{} while(0) 

用法妙用

 

2010-12-10 11:44 

#define 

 

 

do{} while(0) 

什么意思

 

#define 

 

 

do{} while(0) 

为什么这么用

 

什么情况下用宏定义

do{}while(0); 

 

 

简单地说,就是能够实现复杂的定义,通用性强,任

何情况下都适用。

 

 

 

#define MACRO_NAME(para) do{macro content}while(0) 

的格式,总结了以下几个原因:

 

1

,空的宏定义避免

warning: 

 

 

 

 

 

 

#define foo() do{}while(0) 

 

 

2

,存在一个独立的

block

,可以用来进行变量定义,进行比较复杂的实现。

 

3

,如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现:

 

 

 

 

 

 

#define foo(x) \ 

 

 

 

 

 

 

action1(); \ 

 

 

 

 

 

 

action2(); 

 

 

 

 

 

在以下情况下:

 

 

 

 

 

if(NULL == pPointer) 

 

 

 

 

 

 

 

 

 

foo(); 

 

 

 

 

 

 

就会出现

action1

action2

不会同时被执行的情况,而这显然不是程序设计的目的。

 

 

 

 

 

 

 

4

,以上的第

3

种情况用单独的

{}

也可以实现,但是为什么一定要一个

do{}while(0)

呢,

看以下代码:

 

 

 

 

 

 

 

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

 

 

 

 

 

 

 

 

 

 

if(x>y) 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

switch(x,y); 

 

 

 

 

 

 

 

 

else 

 

 

 

 

 

 

//error, parse error before else 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

otheraction(); 

 

 

 

 

 

 

在把宏引入代码中,会多出一个分号,从而会报错。

 

 

 

 

 

 

 

 

 

//------------------------------------------------ 

 

 

 

 

 

 

 

使用

do{….}while(0)

 

把它包裹起来,成为一个独立的语法单元,从而不会与上下文

发生混淆。同时因为绝大多数的编译器都能够识别

do{…}while(0)

这种无用的循环并进行优

化,所以使用这种方法也不会导致程序的性能降低。

 

详解如下:

MFC, 

MFC

afx.h

文件里面,

 

你会发现很多宏定义都是用了

do...while(0)

do...while(false)

 

比如说:

 

#define 

AFXASSUME(cond) 

 

 

 

 

 

 

do 

bool 

__afx_condVal=!!(cond); 

ASSERT(__afx_condVal); __analysis_assume(__afx_condVal); } while(0) 

 

粗看我们就会觉得很奇怪,既然循环里面只执行了一次,我要这个看似多余的

do...while(0)

有什么意义呢?

 

 

当然有!

 

为了看起来更清晰,这里用一个简单点的宏来演示:

 

#define SAFE_DELETE(p) do{ delete p; p = NULL} while(0) 

假设这里去掉

do...while(0), 

#define SAFE_DELETE(p) delete p; p = NULL; 

那么以下代码:

 

if(NULL != p) SAFE_DELETE(p) 

else 

 

 

...do sth... 

就有两个问题,

 

1) 

因为

if

分支后有两个语句,

else

分支没有对应的

if

,编译失败

 

2) 

假设没有

else, SAFE_DELETE

中的第二个语句无论

if

测试是否通过,会永远执行。

 

你可能发现,为了避免这两个问题,我不一定要用这个令人费解的

do...while, 

 

我直接用

{}

括起来就可以了

 

#define SAFE_DELETE(p) { delete p; p = NULL;} 

的确,这样的话上面的问题是不存在了,但是我想对于

C++

程序员来讲,在每个语句后面加

分号是一种约定俗成的习惯,这样的话,以下代码

if(NULL != p) SAFE_DELETE(p); 

else 

 

 

...do sth... 

else

分支就无法通过编译了(原因同上)

,所以采用

do...while(0)

是做好的选择了。

 

 

也许你会说,我们代码的习惯是在每个判断后面加上

{}, 

就不会有这种问题了,也就不需要

do...while

了,如:

 

if(...) 

 

else 

诚然,这是一个好的,应该提倡的编程习惯,但一般这样的宏都是作为

library

的一部分出现

的,而对于一个

library

的作者,他所要做的就是让其库具有通用性,强壮性,因此他不能有

任何对库的使用者的假设,如其编码规范,技术水平等

 

 

 

 

do...while(0)-

妙用

 

 

(

...)sswanglei 

发表于

 

2007-7-1 

22:33:00 

C++

中,有三种类型的循环

语句:

for, while, 

do...while

 

但是在一般应用中作循环时,

 

我们可能用

for

while

要多

一些,

do...while

相对不受重视。

 

 

 

 

 

但是,最近在读我们项目的代码时,却发现了

do...while

的一些十分聪明的用法,不是用

来做循环,而是用作其他来提高代码的健壮性。

 

1. do...while(0)

消除

goto

语句。

 

通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出

函数,当然,退出前先释放资源,我们的代码可能是这样:

 

version 1 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

bool

 bOk(

true

); 

 

 

 

 

// 

执行并进行错误处理

 

 

 

 

bOk = func1(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

bOk = func2(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

bOk = func3(); 

 

 

 

if

(!bOk) 

 

 

 

 

 

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

// ..........

 

 

 

 

 

// 

执行成功,释放资源并返回

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

true

 

 

 

 

 

 

 

这里一个最大的问题就是代码的冗余,而且我每增加一个操作,就需要做相应的错误处理,

非常不灵活。于是我们想到了

goto: 

version 2

 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

bool

 bOk(

true

); 

 

 

 

 

// 

执行并进行错误处理

 

 

 

 

bOk = func1(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

bOk = func2(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

bOk = func3(); 

 

 

 

if

(!bOk) 

goto

 errorhandle; 

 

 

 

 

// ..........

 

 

 

 

 

// 

执行成功,释放资源并返回

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

true

 

errorhandle: 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 

false

 

 

 

 

 

 

 

代码冗余是消除了,但是我们引入了

C++

中身份比较微妙的

goto

语句,虽然正确的使用

goto

可以大大提高程序的灵活性与简洁性,

但太灵

 

活的东西往往是很危险的,

它会让我们的程序

捉摸不定,那么怎么才能避免使用

goto

语句,又能消除代码冗余呢,请看

do...while(0)

循环:

 

version3 

 

bool

 Execute() 

 

 

 

// 

分配资源

 

 

 

 

int

 *p = 

new

 

int

 

 

 

 

bool

 bOk(

true

); 

 

 

 

do

 

 

 

 

 

 

 

 

 

 

// 

执行并进行错误处理

 


 

 

 

 

 

 

bOk = func1(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

bOk = func2(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

bOk = func3(); 

 

 

 

 

 

 

if

(!bOk) 

break

 

 

 

 

 

 

 

// ..........

 

 

 

 

 

}

while

(0); 

 

 

 

 

 

// 

释放资源

 

 

 

 

 

delete p; 

 

 

 

 

 

 

 

p = NULL; 

 

 

 

 

return

 bOk;


<think>好的,用户问的是do while(0)用法和意义。我之前学过一些C语言,记得在宏定义里见过这种写法,但具体为什么不太清楚。先得回忆一下do while的基本结构,通常循环会执行多次,但这里条件为0,也就是false,所以里面的代码块只会执行一次。那为什么要用这样的结构呢? 可能的原因之一是宏定义。比如,在定义多语句的宏时,如果直接用大括号包裹,可能在某些情况下出现问题,比如if语句后面跟宏展开时,分号会导致语法错误。比如: #define FOO() { func1(); func2(); } 然后使用的时候: if (condition) FOO(); else ... 这里展开后,if后面跟着的大括号加上分号,会导致else无法匹配,因为if后面跟的是一个复合语句,而分号会使后面的else无法正确连接。这时候如果用do while(0),就可以解决这个问题,因为do while(0)后面需要加分号,这样宏展开后的结构是正确的。 另一个可能是和break语句结合使用。在do while(0)循环中,可以使用break来提前退出,这样可以将一些条件判断包裹在里面,当某个条件不满足时直接break,避免执行后面的代码。这在复杂的宏定义中可能有用,让宏的行为更像一个函数,可以在任何地方退出。 还有可能涉及到作用域的问题。do while(0)会创建一个块作用域,这样里面定义的变量可以局部化,避免污染外部作用域。这在宏定义中尤其重要,因为宏可能在多处展开,如果不限制作用域,可能会有变量名冲突的问题。 另外,可能和代码结构有关,比如在某些情况下需要将多个语句组合成一个单独的块,而使用do while(0)可以确保代码块被当作一个整体处理,尤其是在条件编译或者复杂的控制流中。 需要验证这些想法是否正确。比如,查找一下宏定义中使用do while(0)的例子,以及是否真的能解决if-else的问题。例如,使用do while(0)的宏展开后会是: if (condition) do { ... } while(0); else ... 这样分号是正确闭合的,不会导致语法错误。而如果不用的话,可能展开成没有分号的块,导致语法错误。 另外,关于使用break来退出,比如在宏中可能有多个条件检查,如果某个条件失败,可以用break跳过后续代码。例如: #define PROCESS_DATA(data) \ do { \ if (!data_valid(data)) break; \ process_step1(data); \ process_step2(data); \ } while(0) 这样在调用PROCESS_DATA时,如果data无效,后面的步骤就不会执行,类似于函数中的提前返回。 总结一下,do while(0)的主要用途在宏定义中,解决语法问题、允许使用break、创建局部作用域。此外,可能还有其他情况,比如在C++中避免变量的作用域问题,或者在某些代码结构中统一代码块。 现在需要将这些整理成用户容易理解的回答,结构清晰,分点说明,并给出示例代码。同时,根据用户提供的引用,可能没有直接相关的引用内容,但如果有的话可以引用。比如,引用[3]提到异步编程的哲学,可能与代码结构有关联,但不确定是否适用。用户提供的引用中,引用[2]涉及并行化框架,可能和代码结构中的多线程有关,但do while(0)可能不直接相关。因此,可能不需要引用这些内容,但需要按照用户要求尽量参考之前的回答。不过根据用户提供的引用,似乎没有直接相关的,所以可能不需要添加引用标识。或者,如果有相关的点可以关联的话可以引用,比如宏定义中的结构可能与代码生成框架有关,如引用[4]的MetaGPT生成结构化输出,但不确定是否相关。可能不需要强行引用,用户给的引用可能只是示例,所以按照要求,回答中引用的段落末尾添加引用标识,但如果没有引用的话可以不加。 最后,生成相关问题,可能需要考虑宏的其他用法、作用域问题、循环结构优化等。</think>在编程中,`do while(0)` 的用法看似反直觉,但其在特定场景下有重要意义,尤其在宏定义和代码结构化中。以下是其核心用途和示例: --- ### 一、`do while(0)` 的核心意义 1. **宏定义中的语法完整性** 在定义多语句宏时,若直接使用 `{...}` 包裹代码,可能因分号或作用域问题导致语法错误。例如: ```c #define FOO() { func1(); func2(); } ``` 当与 `if-else` 结合时: ```c if (condition) FOO(); // 展开后为 { ... }; 导致 else 无法匹配 else ... ``` 改用 `do while(0)` 可确保宏展开后语法正确: ```c #define FOO() do { func1(); func2(); } while(0) ``` 此时 `FOO()` 展开为 `do { ... } while(0);`,分号闭合自然,避免语法问题[^1]。 2. **支持 `break` 提前退出** `do while(0)` 允许在宏中使用 `break` 实现类似函数中的“提前返回”: ```c #define PROCESS_DATA(data) \ do { \ if (!validate(data)) break; \ step1(data); \ step2(data); \ } while(0) ``` 若 `validate(data)` 失败,后续步骤自动跳过。 3. **限制变量作用域** 在 `do while(0)` 内部定义的变量仅在此块内有效,避免污染外部命名空间: ```c #define CALCULATE(x) \ do { \ int temp = (x) * 2; \ printf("%d", temp); \ } while(0) ``` --- ### 二、其他应用场景 1. **代码块统一性** 在条件编译或复杂控制流中,`do while(0)` 可将多个语句组合为单一块,便于统一处理: ```c #ifdef DEBUG #define LOG(msg) do { fprintf(stderr, "[DEBUG] %s\n", msg); } while(0) #else #define LOG(msg) #endif ``` 2. **避免空语句警告** 当宏可能为空时,`do while(0)` 可避免编译器警告: ```c #define EMPTY_MACRO() do { } while(0) ``` --- ### 示例代码 ```c // 使用 do while(0) 的宏定义 #define SAFE_FREE(ptr) \ do { \ if (ptr) { \ free(ptr); \ ptr = NULL; \ } \ } while(0) int main() { int* arr = malloc(10 * sizeof(int)); SAFE_FREE(arr); // 安全释放内存并置空指针 return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值