第8回 続・制御構造を if と goto だけを使って書く

今回は、C言語の制御構造を ifgoto だけを使って書いてみる試みの 2 回目となります。前回は選択文を書き直しましたので、今回は繰り返し文の書き直しを行ってみたいと思います。

do 文

C言語の繰り返し文の中では、do 文は比較的目立たない存在かもしれません。しかし、コンピュータとの相性が最もよいのは do 文であり、効率のよいループを書きたいなら、do 文を使えないかどうか検討してみるべきです。

それでは、早速ですが、次のコードを書き直すことにします。

do
{
  ... /* 処理1 */
  break;
  ... /* 処理2 */
  continue;
  ... /* 処理3 */
} while (expr);

上のコードを書き直すと、

Do:
... /* 処理1 */
goto Enddo; /* break; */
... /* 処理2 */
goto Next;  /* continue */
... /* 処理3 */
Next:
if (expr) goto Do;
Enddo:

のようになります。いきなり breakcontinue も入れてしまったのでやや煩雑になりましたが、基本はループの終端で条件判定を行い、真であればループの最初に戻り、偽であればループから抜けるだけです。

while 文

次は while 文です。do との違いは、条件判定をループの最後で行うか、最初で行うかです。それでは、元になるコードから見てみましょう。

while (expr)
{
  ... /* 処理1 */
  break;
  ... /* 処理2 */
  continue;
  ... /* 処理3 */
}

まずは、上のコードを素直に書き直して見ます。

While:
if (!expr) goto Endwhile;
... /* 処理1 */
goto Endwhile; /* break */
... /* 処理2 */
goto While;    /* continue */
... /* 処理3 */
goto While;
Endwhile:

これでも構わないのですが、多くの場合、より効率を上げるために、コンパイラは次のようなコードを生成することが多いようです。

goto Next;
While:
... /* 処理1 */
goto Endwhile; /* break */
... /* 処理2 */
goto Next;    /* continue */
... /* 処理3 */
Next:
if (expr) goto While;
Endwhile:

もちろん、こちらの方が常に効率がよいとは限らず、繰り返しの回数が非常に少ない場合や、CPU のアーキテクチャによっては最初の方が効率がよくなることもあり得ます。

for 文

最後は for 文です。for 文は、基本的には while 文と同じですが、ループの最初に評価される式と、ループが 1 回繰り返されるごとに評価される式がある点が異なります。それでは元になるコードです。

for (expr1; expr2; expr3)
{
  ... /* 処理1 */
  break;
  ... /* 処理2 */
  continue;
  ... /* 処理3 */
}

while 文のときと同じように、まずは素直に書き直してみます。continue を使った場合でも、expr3 が評価される点にご注意ください。

expr1;
For:
if (!expr2) goto Endfor;
... /* 処理1 */
goto Endfor; /* break; */
... /* 処理2 */
goto Next;  /* continue */
... /* 処理3 */
Next:
expr3;
goto For;
Endfor:

ループの最後で条件判定をする書き方は次のようになります。

expr1;
goto Next;
For:
... /* 処理1 */
goto Endfor; /* break; */
... /* 処理2 */
goto Next;  /* continue */
... /* 処理3 */
expr3;
Next:
if (expr2) goto For;
Endfor:

このように、繰り返し文もすべて ifgoto で書き直すことができます。最初にも書きましたが、実践的なプログラムでわざわざこんな書き方をすることはないでしょうが、一度は試しておくと、それぞれの制御構造の細かな振る舞いを完全に把握することができるようになります。

また、普段はあまり使う機会のない goto ですが、このように使い方を訓練しておけば、本当に必要なときに、適切に goto を使用するための助けとなることでしょう。