C言語のソースコードを読んでいると、
次のように、複数の処理が do-while(0) で囲まれたソースコードを見かけることがあります。
#include <stdio.h>
#define OK 0
#define NG -1
int main( void ){
int ret = NG;
do{
if( OK != funcA() ){
break;
}
if( OK != funcB() ){
break;
}
if( OK != funcC() ){
break;
}
ret = OK;
}while( 0 );
return ret;
}do-while 文は、本来「設定した条件が真の間、処理を繰り返す」ための制御構文です。
しかし、do-while(0) では、条件式が常に偽となるため、ループが繰り返されることはありません。
一見すると、意味のない制御構文のようにも見えますが、
この書き方にも意図された狙いがあります。

do-while(0) が使われる理由について、本記事で整理してまとめています。
do-while(0)とは
do-while 文の基本動作
do-while 文は、while 文とは異なり、
処理を実行したあとに条件式を評価するループ構文です。
基本的な構文は次のとおりです。
do {
処理;
} while (条件式);この構文では、まず do { … } 内の処理が実行され、その後に条件式を評価します。
条件式が真(true)の場合は再び処理が繰り返され、偽(false)の場合はループを抜けます。
そのため、do-while 文は、
「最低でも1回は処理を実行したい」場合に適した制御構文です。
do-while(0) の特徴
do-while(0) には、次のような特徴があります。
- 必ず1回だけ処理が実行される
- break文を使うことで、処理の途中でブロック全体を抜けられる
- 処理群をひとまとまりのブロックとして扱える
この性質を利用することで、複数の処理を順番に実行しつつ、
途中でエラーが発生した場合は、その時点で処理を中断することができます。
本記事の冒頭に記載のソースコードのように、
funcA() ~ funcC() を do-while(0) で囲むことによって、
仮に funcA() で異常が発生した場合、その時点で break 文により処理を中断します。
その結果、funcB() 以降の処理は実行されなくなります。
if文で書いた場合との違い
同様の処理は、if文をネストして書くことでも実現できます。
しかし、処理が増えるにつれてネストが深くなり、
可読性が低下するといったデメリットがあります。
do-while(0) を使うことで、
処理が増えたとしてもフラットな構造で処理の流れを表現できます。
do-while(0)で囲む理由
do-while(0) を使ったソースコードを見て、
「goto文や途中returnで中断したらよいのでは?」と感じる人もいると思います。
筆者自身も、その考え方自体は正しいと思います。
しかし、実際の開発では現場ごとにコーディング規約と呼ばれる独自のルールが定められており、
必ずしもそれらの構文が自由に使えるとは限りません。
break 文を使って処理を中断するため
開発現場によっては、次のようなコーディング規約が存在することがあります。
- goto 文の使用が許されていない
- return 文は1関数につき1つまでと決められている。
(=関数の終端以外での return を禁止)
このような制約がある場合、
処理の途中で関数を抜ける手段が限られてしまいます。
do-while(0) で処理を囲んでおくことによって、
エラー発生時に break 文を実行することで、
関数の末尾まで到達することなく処理を中断できます。

このように、「goto文や途中returnが使えない環境で処理を中断する手段」として、
do-while(0) が用いられることがあります。
苦肉の策と思ってもよいかもしれません……。
処理を1つのブロックとしてまとめるため
do-while(0) で複数の処理を囲むことで、
一連の処理を「ひとつのまとまり」として扱うことができます。
これにより、if 文を多重にネストする必要がなくなるため、
エラー処理の流れを上から順に追いやすくなる点もメリットになります。
この書き方は、特に「前の処理が成功した場合のみ次へ進む」という処理が連続する場面で有効です。
まとめ
do-while(0) は、一見すると意味のないループのように見えますが、
実際には複数の処理をひとつのブロックとしてまとめ、
break 文で途中中断できるようにするための書き方です。
特に、goto 文や途中 return の使用が制限されているコーディング規約の下で、
エラー発生時の処理を分かりやすく記述する手段として利用されています。
初めて見ると不思議な書き方に感じると思います。

このように処理の意図をしっかり理解することが、
ソースコードを読み書きする力に繋がると思います。


コメント