for文やswitch文などの制御構造は、すべてif文とgoto文だけを使って書き直すことができます。もちろん、実践的なプログラミングでそんなことをする必要はまずありませんが、制御構造の正確な動作を把握するためにも、一度は経験しておくとよいでしょう。
また、if文とgoto文だけを使って制御構造を書き直せるようになっておくと、自然に効率のよいコーディングができるようになるほか、逆アセンブルリストをソースコードと対応付けながらデバッグすることも比較的容易になります。
if文
if文とgoto文を使って書き直そうというのに、if文を書き直すというのはどういうことだと思われるかもしれません。しかし、C言語のif文は、副文が複合文であったり、else節を伴ったりするので、結構複雑な構造をしています。これを、最も単純なif (expr) goto label;だけを使って書き直してみます。
まずは、次のコードを書き直すことを考えてみましょう。
0 1 2 3 4 5 |
if (expr) { ... /* 処理 */ } |
上のコードは、次のように書き直すことができます。
0 1 2 3 4 |
if (!expr) goto label; ... /* 処理 */ label; |
今度はelse節がある場合です。
0 1 2 3 4 5 6 7 8 9 |
if (expr) { ... /* 処理1 */ } else { ... /* 処理2 */ } |
上のコードを書き直すと、
0 1 2 3 4 5 6 7 8 |
if (!expr) goto Else ... /* 処理1 */ goto Endif; Else: ... /* 処理2 */ Endif: |
のようになります。このif文の書き直しが基本となりますので、しっかりと把握しておいてください。
switch文
今度はswitch文です。switch文はif文と同じ選択文の仲間ですが、if文よりかなり複雑になっています。
0 1 2 3 4 5 6 7 8 9 10 11 12 |
switch (expr) { case 1: ... /* 処理1 */ break; case 2: ... /* 処理2 */ /* break */ default: ... /* 処理3 */ } |
上記は、switch 文の一通りの要素を盛り込んだコード片です。あえてbreak文を書いたり書かなかったりしています。これを書き直すと、
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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ラベルがあるかによっても、実際にコンパイラが展開するコードは若干変わりますが、基本はこんなところです。また、今回はtempはint型としましたが、exprの型によってはlong型やunsigned int型などになることもあり得ます。
長くなってしまいますので、とりあえず今回は選択文だけを取り上げました。次回は繰り返し文をif文とgoto文だけを使って書き直してみたいと思います。