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

forswitch などの制御構造は、すべて ifgoto だけを使って書き直すことができます。もちろん、実践的なプログラミングでそんなことをする必要はまずありませんが、制御構造の正確な動作を把握するためにも、一度は経験しておくとよいでしょう。

また、ifgoto だけを使って制御構造を書き直せるようになっておくと、自然に効率のよいコーディングが出来るようになるほか、逆アセンブルリストをソースコードと対応付けながらデバッグすることも、比較的容易にできるようになります。

if 文

ifgoto を使って書き直そうというのに、if 文を書き直すというのはどういうことだと思われるかもしれません。しかし、C言語の if 文は、副文が複合文であったり、else 節を伴ったりするので、結構複雑な構造をしています。これを、最も単純な if (expr) goto label; だけを使って書き直そうというわけです。

まずは、次のコードを書き直すことを考えてみましょう。

if (expr)

{
  ... /* 処理 */
}

上のコードは、次のように書き直すことができます。

if (!expr) goto label;
  ... /* 処理 */
label;

今度は else 節がある場合です。

if (expr)
{
  ... /* 処理1 */
}
else
{
  ... /* 処理2 */
}

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

if (!expr) goto Else
  ... /* 処理1 */
  goto Endif;
Else:

  ... /* 処理2 */
Endif:

のようになります。この、if 文の書き直しが基本となりますので、しっかりと把握しておいてください。

switch 文

今度は switch 文です。switch 文は if 文と同じ選択文の仲間ですが、if 文よりはかなり煩雑になっています。

switch (expr)
{
case 1:
  ... /* 処理1 */
  break;
case 2:
  ... /* 処理2 */
  /* break */
default:
  ... /* 処理3 */
}

上記は、switch 文の一通りの要素を盛り込んだコード片です。これを書き直すと、

int temp = expr;
if (temp == 1) goto Case_1;
if (temp == 2) goto Case_2;
goto Default;

Case_1:
  ... /* 処理1 */
  goto Endswitch;
Case_2:
  ... /* 処理2 */
  /* goto Endswitch; */
Default:
  ... /* 処理3 */
Endswitch:

のようになります。処理系によっても、どんな case ラベルがあるかによっても、実際にコンパイラが展開するコードは若干変わりますが、基本はこんなところです。また、今回は tempint 型としましたが、expr の型によっては long 型や unsigned int 型になることもあり得ます。


長くなってしまいますので、とりあえず今回は選択文だけを取り上げました。次回は繰り返し文を ifgoto だけを使って書き直してみたいと思います。