do-while文 (英: do-while statement) は、C言語および類似のプログラミング言語において繰り返し(ループ)の制御構造を記述するための文 (statement) のひとつである。C言語の規格では「do文」と呼ばれる[1]。ループ本体 (loop body) [2]の処理を一度実行した後、さらに継続条件として指定された式(制御式)を評価した値が真である間、ループ本体を繰り返し実行する。while文との違いは、ループに入る前の条件の評価が無く最初に必ず1回はループ本体が実行されることである。
なお、C言語およびC++ではゼロに等しい値を偽、ゼロ以外を真とみなす。したがって、整数型だけでなく、任意のポインタ型や浮動小数点数型の式も制御式として記述可能である[注釈 1]。C/C++以外のブーリアン型をサポートするほとんどの言語では通例、制御式にはブーリアン型の式のみを記述できる。
C言語および類似の言語では以下のような構文である。
do
文 /* ここの部分を「ループ本体」と呼ぶ */
while (条件);
このループの実行は、次のような手順となる。
「条件」がはじめから偽の場合も、「文」は一度実行される。
ループ本体が複数の文からなる場合、ブロック(複文)を使う。
do {
...
} while (条件);
C言語のプログラム例:
int x = 0;
do {
x += 1;
} while (x < 3);
この例では、最初に x += 1
を実行し x == 1
となる。次に条件の x < 3
をチェックする。条件は真であり、コードブロックを再度実行する。変数 x
がループ脱出条件に合致する(x >= 3
になる)まで、コードの実行と条件のチェックを繰り返す。
C言語に似ていない言語では、異なった構文で同様の機能を持つものもある(while文の記事も参照)。例えばPascalでは、"repeat-until" 文である。ただし、制御式として継続条件ではなく終了条件(真のときループを終了)を記述する。
なお、Fortran (Fortran 90以降) にもdo-while文はあるが、これはC言語のwhile文と同等であり、制御式を前置する。以下の例では、ループ本体は一度も実行されない。
program TEST
integer x
data x /0/
do while (x > 0)
print *, x
x = x - 1
end do
print "('Finished. x = ', i0)", x
end
while文と同様、do-while文においてもbreak文などの分岐文を使用できる。なお、continue文はループの途中から、ループ本体の最後に飛び[3]、do-while文の場合には条件の評価となる。
以下の、各言語によるdo-while文あるいは同様の制御を利用したプログラムは、与えられた数の階乗を計算する。
Adaの例。
with Ada.Integer_Text_IO;
procedure Factorial is
Counter : Integer := 5;
Factorial : Integer := 1;
begin
loop
Factorial := Factorial * Counter;
Counter := Counter - 1;
exit when Counter = 0;
end loop;
Ada.Integer_Text_IO.Put(Factorial);
end Main;
Dim counter As UInteger = 5
Dim factorial as ULong = 1
Do
factorial *= counter ' multiply
counter -= 1 ' decrement
Loop While counter > 0
System.Console.WriteLine(factorial)
unsigned int counter = 5;
unsigned long factorial = 1;
do {
factorial *= counter--; /* Multiply, then decrement. */
} while (counter > 0);
printf("%lu\n", factorial);
C#の例。
uint counter = 5;
ulong factorial = 1;
do
{
factorial *= counter--;
}
while (counter > 0);
System.Console.WriteLine(factorial);
D言語の例。
uint counter = 5;
ulong factorial = 1;
do {
factorial *= counter--;
} while (counter > 0);
writeln(factorial);
Javaの例。
int counter = 5;
long factorial = 1;
do {
factorial *= counter--; // Multiply, then decrement.
} while (counter > 0);
System.out.println(factorial);
Pascalの例。
program FactorialProgram;
var
counter, factorial: Integer;
begin
counter := 5;
factorial := 1;
repeat
factorial := factorial * counter;
counter := counter - 1;
until counter = 0;
Write(factorial);
end.
C/C++におけるdo-while文の特殊な用法に、最後にセミコロンが付く構文であることを利用し、展開結果にブロックを含むマクロの呼び出しを関数のように見えるものにする、というイディオムがある。
/* 2つの値 x, y を入れ替えるマクロ。 */
#define SWAP(x, y, tmp) do { (tmp) = (x); (x) = (y); (y) = (tmp); } while (0)
/* 以下のように書いてしまうと、セミコロンを付けた場合にコンパイルが通らなくなるケースがある。 */
/*
#define SWAP(x, y, tmp) { (tmp) = (x); (x) = (y); (y) = (tmp); }
*/
void some_function()
{
int x, y, tmp;
...
if (x > y)
SWAP(x, y, tmp);
else
puts("Not swapped.");
...
}
これを利用することで、「セミコロンを付けてはいけないマクロ」という、扱いが面倒なものを作らずにすむ[4]。