3

入れ子になったループから飛び出すなど、GOTO が役立つ PL/SQL プログラムをいくつか作成しました。

他の言語で goto を使用するのは本当に悪い考えなのか、私は疑問に思っていました。(たとえば、C++)。

私はこれらの質問を見つけました:

GOTO はまだ有害と見なされていますか?

C++ コンパイラの最適化に対する goto の効果

「コンパイラは通常、goto を含むコードを最適化できません」という回答があります。

もう 1 つは、「ただし、通常のフロー制御ステートメント (ループ、スイッチなど) では作成できない goto を使用してフロー グラフを作成することは可能です。」

それは goto の悪だと言われたことがありますが、goto を含むコードを読むのが恐ろしいことを除いて、誰もその理由を教えてくれませんでした。ええと、それらが「悪」であるために誰もそれらの使用方法を学び、理解しなければ、誰もそれらを読むことができません.

コンパイラが GOTO を含むコードを最適化できる場合と最適化できない場合はどのような場合ですか? なんで?

4

1 に答える 1

2

大きな脂肪の免責事項:

他の言語で goto を使用するのは本当に悪い考えなのか、私は疑問に思っていました。(たとえば、C++)。

1 つの例外 (以下で説明する C) を除いて、多くの規律が組み合わされていますが、それが良い考えになることはほとんどありません。これは言語に依存するため、地元の第一人者に尋ねてください。ただし、適切なユースケースが見つかる可能性はかなり低いです。注意が必要です。この言語には、あなたが使いたいと思っていることを行うための、より慣用的で明確な方法がある可能性がありますgoto


それは、「絶対に不可能」または「問題を停止することは不可能」というよりも、「単に非現実的」なケースです。場合によっては、特に手動で同等gotoの s を記述してループを非表示にしている場合 (なんと愚かなことをすることでしょう!)、偶然うまくいくことがあります。それ以外の場合、特に制御フロー グラフがスパゲッティに似ているか、奇妙/異常である場合、コンパイラは何も最適化できません。

最適化パスの作成に費やせる時間と思考は限られており、コンパイラが最適化パスの実行に費やすことができる時間も限られています。ほとんどの言語に組み込まれている、広く使用され、よく理解されている制御フロー パターン (whileループ、開始時に既知のトリップ カウントを持つループ、初期returnの 、switch、 のチェーンelse ifなど) に焦点を当てることは、はるかにやりがいがあります。のみをサポートする IR で最適化が行われる場合でもgoto-esque 制御フロー、これらのパターンは、予測可能で簡単に認識できる偽装につながり、最適化はそれらを探すように調整されます。これは、あなたが引用した 2 番目の文が語っていることです。コードがループとはまったく異なる方法で前後にジャンプする場合、ループ展開パスは、それが実際には巧妙な (悪い種類の巧妙な) 書き方であっても、その日の時刻を提供しません。 "。

これまでは、goto標準 C のような a を想定してきました。つまり、ターゲット ラベルは静的に認識され、他の言語構造を尊重するように制限されています (たとえば、1 つの関数内でのみジャンプする)。動的に選択された任意のターゲットにジャンプできる拡張機能があります (例: "computed goto")。これらは、おそらく関数ポインターと同じ球場で、分析 (したがって最適化) がはるかに困難です。

それは goto の悪だと言われたことがありますが、goto を含むコードを読むのが恐ろしいことを除いて、誰もその理由を教えてくれませんでした。ええと、それらが「悪」であるために誰もそれらの使用方法を学び、理解しなければ、誰もそれらを読むことができません.

それからあなたに言った人たちは悪い仕事をしました。これは問題ではないので、簡単に説明します。制御フローの 99% は、特殊な制御フロー構造を保証する非常に少数のカテゴリに当てはまります。これらすべてのケースで単一の構造体 GOTO を使用すると、意図がわかりにくくなり、コードが多くなり、コードが何をしているかを大まかに理解するのに時間がかかります。これを直接体験できます。100 行を超えるかなり複雑なバッチ ファイルをいくつか作成します (あの恐ろしい古代の Windows スクリプト言語)。

ああ、もう 1 つ:

ネストされたループから飛び出すなど、GOTO が役立つことがわかりました

これは良い使い方かもしれませんが、ほとんどの言語はそれを行うためのより明確な方法を提供しています。あるいは、ループを (たとえば Python の でitertools.combinations) とを平坦化するbreakか、ネストされたループを別の関数に入れます (とにかく多くの場合は良い考えです) とreturn.

さらに、これらの良い用途ですgoto。たとえば、C でのエラー処理などです。これらのユース ケースは多くの場合、単純なパターンにも準拠していますが、言語に組み込まれていないパターンであるため、使用せずに済ます必要があります。

于 2013-07-19T20:38:48.727 に答える