Bjarne Stroustrup(C++创建者)曾说过他避免使用"do/while"循环,而更喜欢用"while"循环编写代码.[见下面的引文.]
听到这个,我发现这是真的.你的想法是什么?是否有一个例子,"do/while"比使用"while"更清晰,更容易理解?
回答一些答案:是的,我理解"do/while"和"while"之间的技术差异.这是一个关于可读性和构造涉及循环的代码的更深层次的问题.
让我问另一种方式:假设你被禁止使用"do/while" - 是否有一个现实的例子,这会让你别无选择,只能使用"while"编写不干净的代码?
从"The C++ Programming Language",6.3.3:
根据我的经验,do-statement是错误和混乱的根源.原因是它的主体总是在评估条件之前执行一次.然而,为了使身体正常工作,非常像条件的东西必须在第一次通过时才能保持.比我想象的更频繁,我发现在程序第一次编写和测试时,或者在修改之前的代码之后,条件不能按预期保持. 我也更喜欢条件"我可以看到它的前方".因此,我倾向于避免做声明.-Bjarne
Dav*_*jak 89
是的我同意while循环可以重写为while循环,但是我不同意总是使用while循环更好.总是至少运行一次,这是一个非常有用的属性(最典型的例子是输入检查(从键盘))
#include <stdio.h>
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
Run Code Online (Sandbox Code Playgroud)
这当然可以重写为while循环,但这通常被视为更优雅的解决方案.
sha*_*oth 38
do-while是一个带有后置条件的循环.在循环体至少执行一次的情况下需要它.这对于在可以合理评估循环条件之前需要一些动作的代码是必要的.使用while循环,您必须从两个站点调用初始化代码,而您只能从一个站点调用它.
另一个例子是当你要启动第一次迭代时已经有一个有效的对象,所以你不希望在第一次迭代开始之前执行任何操作(包括循环条件评估).一个例子是FindFirstFile/FindNextFile Win32函数:你调用FindFirstFile,它会向第一个文件返回一个错误或一个搜索句柄,然后你调用FindNextFile直到它返回一个错误.
伪代码:
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*son 17
do { ... } while (0)
是使宏行为良好的重要结构.
即使它在实际代码中并不重要(我不一定同意),但对于修复预处理器的一些缺陷也很重要.
编辑:我遇到了一个情况,在我自己的代码中今天做/更清洁.我正在对配对的LL/SC指令进行跨平台抽象.这些需要在循环中使用,如下所示:
do
{
oldvalue = LL (address);
newvalue = oldvalue + 1;
} while (!SC (address, newvalue, oldvalue));
Run Code Online (Sandbox Code Playgroud)
(专家可能会意识到旧的值在SC实现中未被使用,但它包含在内以便可以使用CAS模拟这种抽象.)
LL和SC是一个很好的例子,其中do/while比同等形式更清晰:
oldvalue = LL (address);
newvalue = oldvalue + 1;
while (!SC (address, newvalue, oldvalue))
{
oldvalue = LL (address);
newvalue = oldvalue + 1;
}
Run Code Online (Sandbox Code Playgroud)
出于这个原因,我对Google Go 选择删除do-while结构这一事实感到非常失望.
当你想"做"某事"直到"满足条件时,它是有用的.
它可以像这样在while循环中捏造:
while(true)
{
// .... code .....
if(condition_satisfied)
break;
}
Run Code Online (Sandbox Code Playgroud)
在我们的编码约定中
所以我们几乎从来没有do {} while(xx)
因为:
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
Run Code Online (Sandbox Code Playgroud)
被改写为:
int main() {
char c(0);
while (c < '0' || c > '9'); {
printf("enter a number");
scanf("%c", &c);
}
}
Run Code Online (Sandbox Code Playgroud)
和
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
Run Code Online (Sandbox Code Playgroud)
被改写为:
Params params(xxx);
Handle handle = FindFirstFile( params );
while( handle!=Error ) {
process( params ); //process found file
handle = FindNextFile( params );
}
Run Code Online (Sandbox Code Playgroud)
以下常见习语对我来说似乎非常简单:
do {
preliminary_work();
value = get_value();
} while (not_valid(value));
Run Code Online (Sandbox Code Playgroud)
要避免的重写do
似乎是:
value = make_invalid_value();
while (not_valid(value)) {
preliminary_work();
value = get_value();
}
Run Code Online (Sandbox Code Playgroud)
第一行用于确保测试始终在第一次评估为true.换句话说,第一次测试总是多余的.如果没有这个多余的测试,也可以省略初始分配.此代码给人的印象就是它会自己打架.
在像这样的情况下,do
构造是一个非常有用的选择.
首先,我确实同意 其do-while
可读性低于while
.
但令我惊讶的是,在这么多答案之后,没有人考虑过为什么do-while
这种语言存在。原因是效率。
假设我们有一个do-while
带有条件检查的循环N
,其中条件的结果取决于循环体。然后,如果我们用循环替换它while
,我们就会得到N+1
条件检查,而额外的检查是毫无意义的。如果循环条件仅包含对整数值的检查,那没什么大不了的,但假设我们有
something_t* x = NULL;
while( very_slowly_check_if_something_is_done(x) )
{
set_something(x);
}
Run Code Online (Sandbox Code Playgroud)
那么循环第一圈中的函数调用是多余的:我们已经知道x
尚未设置任何内容。那么为什么要执行一些无意义的开销代码呢?
在编写实时嵌入式系统时,我经常为此目的使用 do-while,其中条件内的代码相对较慢(检查某些慢速硬件外设的响应)。
这都是关于可读性的.
更易读的代码可以减少代码维护和更好的协作.
到目前为止,其他考虑因素(例如优化)在大多数情况下并不那么重要.
我会详细说明,因为我在这里得到了一个评论:
如果你有一个使用的代码片段A,do { ... } while()
它比while() {...}
同等的B更具可读性,那么我就投票给A了.如果你喜欢乙,因为你看到的循环条件"前面",你认为这是更具可读性(因此维护等) -那么请便,用乙.
我的观点是:使用对您的眼睛(以及您的同事)更具可读性的代码.当然,选择是主观的.
这是我见过的最干净的 do-while 替代方法。这是推荐用于没有 do-while 循环的 Python 的习惯用法。
一个警告是你不能有continue
in ,<setup code>
因为它会跳过中断条件,但是显示 do-while 好处的例子都不需要在条件之前继续。
while (true) {
<setup code>
if (!condition) break;
<loop body>
}
Run Code Online (Sandbox Code Playgroud)
在这里,它应用于上述 do-while 循环的一些最佳示例。
while (true) {
printf("enter a number");
scanf("%c", &c);
if (!(c < '0' || c > '9')) break;
}
Run Code Online (Sandbox Code Playgroud)
下一个例子是结构比 do-while 更具可读性的情况,因为条件保持在顶部附近,//get data
通常很短,但//process data
部分可能很长。
while (true) {
// get data
if (data == null) break;
// process data
// process it some more
// have a lot of cases etc.
// wow, we're almost done.
// oops, just one more thing.
}
Run Code Online (Sandbox Code Playgroud)