do {} while (0) 用法

本文探讨了在C/C++中使用do{...}

#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)这种无
用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。

为什么很多linux内核中宏#defines用do { ... } while(0)?

有很多原因:

Dave Miller的说法):

             编译器对于空语句会给出告警,这是为什么#define FOO do{ }while(0);


              给定一个基本块(局部可视域),定义很多局部变量;

(Ben Collins的说法):

             在条件代码中,允许定义复杂的宏。可以想像有很多行宏,如下代码:

  • #define FOO(x) /
             printf("arg is %s/n", x); /
             do_something_useful(x);
    现在,想像下面的应用:
    if (blah == 2)
             FOO(blah);
    展开后代码为:
    if (blah == 2)
             printf("arg is %s/n", blah);
             do_something_useful(blah);;
  • 就像你看到的,if仅仅包含了printf(),而do_something_useful()调用是无条件调用。因此,如果用do { ... } while(0),结果是:
  • if (blah == 2)
             do {
                     printf("arg is %s/n", blah);
                     do_something_useful(blah);
             } while (0);
  • 这才是所期望的结果。
  • (Per Persson的说法):
  • 像 Miller and Collins指出的那样,需要一个块语句包含多个代码行和声明局部变量。但是,本质如下面例子代码:
  • #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
  • 上面代码在有些时候却不能有效工作,下面代码是一个有两个分支的if语句:
  • if (x > y)

             exch(x,y);           // Branch 1
    else  
             do_something();      // Branch 2
  • 展开后代码如下:
  • if (x > y) {                 // Single-branch if-statement!!!
             int tmp;             // The one and only branch consists
             tmp = x;             // of the block.
             x = y;
             y = tmp;
    }
    ;                            // empty statement
    else                         // ERROR!!! "parse error before else"
             do_something();
  • 问题是分号(;)出现在块后面。解决这个问题可以用do{}while(0):
  • if (x > y)
             do {
                     int tmp;
                     tmp = x;
                     x = y;
                     y = tmp;
             } while(0);
    else
             do_something();
  •  Bart Trojanowski的说法):
  • Gcc加入了语句解释,它提供了一个替代do-while-0块的方法。对于上面的解决方法如下,并且更加符合常理
  • #define FOO(arg) ({ /

                typeof(arg) lcl; /
                lcl = bar(arg);   /
                lcl;              /
         })
<think> 我们正在讨论C++中的do-while循环。do-while循环是一种后测试循环,即循环体至少执行一次,然后在循环体的末尾测试条件。如果条件为真,则再次执行循环体,否则退出循环。 ### do-while循环的基本语法 ```cpp do { // 循环体:需要重复执行的代码 } while (condition); // 注意分号 ``` ### 代码示例 以下是一个简单的示例,使用do-while循环让用户输入一个正整数,直到输入有效为止: ```cpp #include <iostream> using namespace std; int main() { int num; do { cout << "请输入一个正整数: "; cin >> num; if (num <= 0) { cout << "输入无效,请重新输入!" << endl; } } while (num <= 0); // 当输入的数小于等于0时,继续循环 cout << "您输入的正整数是: " << num << endl; return 0; } ``` ### 代码解释 1. **循环体**:程序首先执行循环体内的代码,提示用户输入一个整数,然后读取输入。 2. **条件检查**:在循环体的末尾,检查条件`num <= 0`。如果条件为真(即输入的数不是正整数),则继续循环,要求用户重新输入;否则,退出循环。 3. **至少执行一次**:即使第一次输入就满足条件(即输入的是正整数),循环体也已经执行了一次。 ### 与while循环的区别 - **while循环**:先测试条件,如果条件为假,则循环体一次都不执行。 - **do-while循环**:先执行循环体,再测试条件,因此循环体至少执行一次。 ### 使用场景 当你需要至少执行一次循环体时,使用do-while循环。例如: - 显示菜单并等待用户选择,直到选择退出。 - 读取用户输入,直到输入有效。 ### 另一个例子:菜单选择 ```cpp #include <iostream> using namespace std; int main() { char choice; do { cout << "菜单选项:" << endl; cout << "1. 选项一" << endl; cout << "2. 选项二" << endl; cout << "q. 退出" << endl; cout << "请选择: "; cin >> choice; switch(choice) { case '1': cout << "执行选项一..." << endl; break; case '2': cout << "执行选项二..." << endl; break; case 'q': cout << "退出程序..." << endl; break; default: cout << "无效选项,请重新选择!" << endl; } } while (choice != 'q'); // 当选择不是'q'时继续循环 return 0; } ``` ### 注意事项 1. 在do-while循环的条件后面必须有一个分号`;`。 2. 循环体内应有改变循环条件的语句,否则可能造成无限循环。 §§相关问题§§: 1. do-while循环和while循环在哪些场景下不能互换? 2. 在do-while循环中,如果条件一开始就为假,循环体执行几次? 3. 如何避免do-while循环中的无限循环? 4. 在C++中,do-while循环能否嵌套使用?请举例说明。 </think># C++中`do-while`循环的详细使用方法 `do-while`循环是C++中的一种后测试循环结构,它先执行循环体,然后再检查循环条件。这意味着循环体**至少会执行一次**,无论初始条件是否满足。 ## 基本语法 ```cpp do { // 循环体(需要重复执行的代码) } while (condition); // 注意分号 ``` ## 关键特性 1. **后测试**:先执行循环体,再检查条件 2. **至少执行一次**:无论初始条件如何,循环体至少执行一次 3. **条件为真时继续**:如果条件表达式结果为`true`,循环继续执行 ## 完整代码示例 ```cpp #include <iostream> using namespace std; int main() { int count = 0; // 基本do-while示例 cout << "基本do-while示例:" << endl; do { cout << "循环次数: " << count << endl; count++; } while (count < 5); cout << "\n------------------------\n"; // 输入验证示例 int number; do { cout << "请输入1到10之间的数字: "; cin >> number; if(cin.fail()) { cin.clear(); // 清除错误状态 cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 清空缓冲区 cout << "输入无效,请重新输入!" << endl; number = -1; // 设置无效值以继续循环 } else if(number < 1 || number > 10) { cout << "数字必须在1到10之间!" << endl; } } while(number < 1 || number > 10); cout << "您输入的有效数字是: " << number << endl; cout << "\n------------------------\n"; // 菜单系统示例 char choice; do { cout << "\n菜单选项:" << endl; cout << "1. 选项一" << endl; cout << "2. 选项二" << endl; cout << "3. 选项三" << endl; cout << "q. 退出" << endl; cout << "请选择: "; cin >> choice; switch(choice) { case '1': cout << "执行选项一..." << endl; break; case '2': cout << "执行选项二..." << endl; break; case '3': cout << "执行选项三..." << endl; break; case 'q': cout << "退出程序..." << endl; break; default: cout << "无效选择,请重试!" << endl; } } while(choice != 'q'); return 0; } ``` ## 代码解释 ### 1. 基本do-while示例 ```cpp int count = 0; do { cout << "循环次数: " << count << endl; count++; } while (count < 5); ``` - 循环从0开始,输出0到4 - 循环体至少执行一次(即使初始条件不满足) - 每次循环后检查`count < 5`条件 ### 2. 输入验证示例 ```cpp do { // 提示输入 // 检查输入是否有效 if(cin.fail()) { // 处理非数字输入 } else if(number < 1 || number > 10) { // 处理范围外数字 } } while(number < 1 || number > 10); ``` - 用户必须输入有效的1-10之间的数字才能退出循环 - `cin.fail()`检查输入失败(如输入字母) - `cin.clear()`清除错误状态 - `cin.ignore()`清空输入缓冲区 ### 3. 菜单系统示例 ```cpp do { // 显示菜单 // 获取用户选择 switch(choice) { // 处理不同选择 } } while(choice != 'q'); ``` - 典型的菜单系统结构 - 用户可以选择不同选项 - 输入'q'退出循环 - 无效选择会提示重新输入 ## 与`while`循环的对比 | 特性 | `do-while`循环 | `while`循环 | |------|----------------|-------------| | **执行顺序** | 先执行循环体,再检查条件 | 先检查条件,再执行循环体 | | **最少执行次数** | 至少执行一次 | 可能一次都不执行 | | **适用场景** | 输入验证、菜单系统 | 条件依赖循环体结果的情况 | | **语法** | 以分号结束 | 没有结束分号 | ## 最佳实践 1. **输入验证**:最适合需要至少获取一次用户输入的场景 2. **菜单系统**:构建交互式菜单的理想选择 3. **避免无限循环**:确保循环体内有改变循环条件的语句 4. **合理使用分号**:注意`do-while`循环以分号结束 5. **代码可读性**:对于复杂的循环体,使用注释明确循环目的
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值