问题描述
出于熟悉,我习惯于使用 while
循环——甚至没有考虑使用 while
或 do-while
循环是否更有趣。以下是 do
与 while
循环的两个示例:
// do-while vs. while --
char *string = "String!";
int pos_d=0,pos_w=0;
// while
while (string[pos_w] != 0) {
printf("At Pos %d The letter is: %c\n",pos_w,string[pos_w]);
pos_w ++;
}
// do-while
do {
printf("At Pos %d The letter is: %c\n",pos_d,string[pos_d]);
} while (string[pos_d++] != 0);
显然在上述情况下,后一个循环允许我们看到字符串中的最后一个字符 (\0
) 而 while 循环在遇到该字符时退出。在 do
循环上使用 while
循环的示例有哪些?例如,如果需要,不能通过在循环后添加相同的复合语句来摆脱 do
循环。在哪些情况下 do
循环比 while 循环更好(并且应该鼓励)?
解决方法
C 语言旨在允许即使是非常简单的编译器也能生成相当高效的机器代码。虽然可以将 while(condition) {block};
表示为 if (condition) do {block} while(condition);
或将 do {block} while(condition);
表示为 if (1) {block} do {block} while (condition);
,但简单的编译器通常会为这些编写相同内容的替代方式生成稍微不同的代码,不同的代码编写方式会在不同的情况下产生更好的结果。
例如,编译器处理 while(condition) {block};
的常用方法是将其视为等同于:
loop:
if (!condition) goto exit;
{block};
goto loop;
exit:
或作为
goto end;
loop:
{block};
end:
if (condition) goto loop;
如果将代码重写为 if (condition) do {block} while(condition);
,结果将等同于:
if (!condition) goto exit;
loop:
{block};
if (condition) goto loop
exit:
除了被采用的条件分支(T)、不采用的条件分支(N)和无条件跳转(U)之外,所有这些执行的代码都是相同的。分支和跳转的成本因平台而异,但可以确定每种代码编写方式需要多少种分支或跳转。特别是,对于三种编写代码的方式,计数为:
--First-- --Second-- --Third--
T N U T N U T N U
Zero iterations: 1 0 0 0 1 1 1 0 0
One iteration: 1 1 1 1 1 1 0 2 0
Addl. iteration: 0 1 1 1 0 0 1 0 0
请注意,对于任意次数的迭代,第三种方法需要最少的分支和跳转,但以重复测试条件所需的代码为代价。在无条件分支和未采用的条件分支的组合成本将超过采用条件分支的成本的系统上,在循环执行零次的情况下,第一种方法会更便宜,如果循环执行,成本将相同只执行一次,如果循环执行两次或更多次,第二次会更便宜。
如果知道循环总是至少执行一次,则可以从第三种方法中消除重复的条件测试和未采用的分支,使其成为非常明显的赢家。编译器生成代码也比第二种方法更容易。在语言中使用 do {} while()
结构可以让简单的编译器在这种情况下更轻松地生成高效的代码。
假设您编写了一些游戏。如果有人打开程序,那么他应该至少想玩一次,对吗?
int replay;
do
{
// Game logic goes here
//Game finishes
printf("Wanna play again? Press 1 to replay. Press other number to quit. Your option: ");
scanf("%d",&replay);
} while(replay == 1);
当然可以:
int replay = 1;
while(replay == 1)
{
//Game logic goes here
//Game finishes
printf("Wanna play again? Press 1 to replay. Press other number to quit. Your option: ");
scanf("%d",&replay);
}
但是在这样的场合使用 do while
可能更具可读性,您不同意吗?
如果你想至少执行一次循环体并在之后检查循环条件,你应该使用 do-while 循环。 它为您的同事提供了比例如更好的可读性和可维护性。使用一些计数器变量。
当你能保证至少有一次迭代时,你至少可以每次都使用 do-while 循环。
我想到的一个具体例子是解析器。在那里,我经常看到很多 do-while 循环。