比较 while 和 do-while 循环

Comparing while vs do-while loops

我习惯于执行 while 循环——甚至不考虑使用 whiledo-while 循环是否更有趣——出于熟悉.以下是 dowhile 循环的两个示例:

// 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);

显然在上述情况下,后一个循环允许我们看到字符串中的最后一个字符 ([=16=]),而 while 循环在遇到该字符时退出。 do 循环用于 while 循环的例子有哪些?例如,如果需要,是否可以通过在循环之后添加相同的复合语句来摆脱 do 循环。在哪些情况下 do 循环比 while 循环更好(应该鼓励)?

如果您想至少执行一次循环体并在之后检查循环条件,则应使用 do-while 循环。 它为您的同事提供了比例如更好的可读性和可维护性。使用一些计数器变量。

在保证至少有一次迭代的情况下,可以至少每次都使用do-while循环

我想到的一个具体例子是解析器。在那里,我经常看到很多 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 可能更具可读性,你同意吗?

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() 结构可以让简单的编译器更轻松地生成高效代码。