C / C ++のgoto演算子に対するあなたの態度は何ですか? ほとんどの場合、プログラミングを学んだときにそれを使用しました。 それからあなたはそれが悪いことを知り、それを忘れました。 複雑なエラー処理を伴うこともありますが、いや、いや、試してみてください... throw ... catch。 またはネストされたループを終了するには...いいえ、フラグと多くの困難があります。 または、ネストされたスイッチが...いいえ、いいえ、いいえ、同じフラグがある場合。
それでも、夜の静寂の中で、あなたは潜在意識に罪深い思考を許しました-「 ここで gotoを使用しないのはなぜですか? そして、このプログラムはよりスリムに見えるようで、最適な形で登場します。 はい、それは良いでしょう...しかし、いいえ- それは不可能です 、彼らは忘れていました!」
なぜそうですか?
カットの下で、長年の経験とさまざまなプラットフォームに基づいて、この問題に対する小さな調査と私の態度があります
UPD:ここでは、PCおよびわずかにマイクロコントローラー用のプログラミングであるCおよびC ++について説明します。 特にマイクロコントローラについては別の記事があります。
gotoの熱烈な反対者へのリクエスト-私がこのトピックを提起し、gotoの部分的な支持者であるという理由だけで、私をマイナスカルマの地獄の火に倒さないでください!
歴史的小旅行
組み合わせ回路、メモリ付き回路が何であるか、そしてアセンブラーがこれからどのように成長したかを完全によく知っている人のために、私たちは安全に結論にスキップすることができます。
そして、それはすべて組み合わせ回路から始まりました
最初は言葉でした-そして言葉は機能でした。 それが論理変数のブール関数であることはそれほど重要ではありません-それに基づいて、彼らはすべての(ほぼ)数学、そしてテキスト、グラフィックスを実装することに成功しました...とにかく、コンピュータ技術を使用すると非常に便利であることが判明しました算術、次に三角法およびその他のアクションを実行し、変数の関数の値を見つけます。
つまり、変数の値によって関数の値を見つけるデバイスを作成する必要がありました。
この困難な問題を解決するために、算術演算を実行するための逐次アルゴリズムが構築されました(このようなアルゴリズムで計算の精度が一定の場合、各算術演算は1クロックサイクルで実行できます)。
アルゴリズムを使用することで、組み合わせ回路を構築することは難しくありません-即座に(論理デバイスの動作と信号の伝播時間まで)出力で答えを出す回路。
問題は、ここで移行が必要ですか? いいえ、彼らは単にそこにいません。 一貫した行動方針があります。 最終的に、これらのすべてのアクションは単一のクロックサイクルで実装できます(私は主張しませんが、非常に面倒になりますが、すべてのデータのビット深度を考えると、学生はVHDLまたはVerilogのシンセサイザーは言うまでもなく、そのようなスキームを構築します)
しかし、その後、メモリ回路が介入しました
そして、誰かのスマートヘッドがフィードバック回路(RSトリガーなど)を思いつきました。 そして、回路の状態が現れました。 そして、状態はメモリを持つすべての要素の現在の値に他なりません。
このようなメモリエレメントの出現により、ハードワイヤードデバイスからファームウェアへの革新的な進歩が可能になりました。 簡単に言うと、ファームウェアにはコマンドメモリがあります。 現在のファームウェア(加算、減算、またはその他)を実装する別のデバイスがあります。 しかし、別のデバイスが「現在の」ファームウェアの選択に関与しています-それを「サンプリングデバイス」にします。
問題は、移行があるかどうかです。 間違いなくはい! さらに、無条件の遷移(次のコマンドのアドレスはデータの現在の状態に依存しない)と条件付き(次のコマンドのアドレスはデータの状態に依存する)が表示されます。
それらなしで行うことは可能ですか? まさか! 遷移を使用しない場合、メモリなしで組み合わせ回路に戻ります。
その結果、アセンブラーに来ました
そのようなコンピューティングデバイスの神格化は、マイクロコンピューター、シンプルコンピューター、スーパーコンピューターになりました。 それらはすべて、基本的にほぼ同じコマンドセットでアセンブラーに簡単に変換できるコード言語に基づいています。 Assemblerを搭載した最も人気のあるパーソナルコンピューターをi386プロセッサーから入手してください。WindowsXPはそのために書かれています。 彼の作品はどのように構成されていますか?
このプロセッサでは、データと命令のメモリが共有され、アドレスによって識別されます。 チームには固定長がありません。 ジャンプコマンドを使用しない場合、次のコマンドは現在のコマンドの直後にあるコマンドを実行します。
gotoコマンドのセットもあります。 これらは無条件(次のアドレスへの切り替え-jmp、サブプログラムへの切り替え-呼び出し、終了-ret、割り込みの呼び出し-int)および条件付き(フラグの状態に応じて-jnz、jne、jz、...)です。 ループを作成するためのコマンドもあります-ループ。 1)CX / ECXレジスタに-1を行い、2)このレジスタがゼロ以外の場合、指定されたアドレスに進みます。
遷移操作に関しては、他のマスアセンブラー(同じマイクロコントローラー)は本質的に同じです-プログラム的に割り込みを発生させる方法がなく、ループがある場所を除きます。
私はすべての責任を宣言します- アセンブラーでの遷移操作なしに行うことは不可能です! アセンブラーのプログラムはどれも目を奪います! ただし、ここで私と主張する人はいません。
まとめ
要約すると何ができますか? マイクロプロセッサレベルでは、移行操作が非常に積極的に使用されます。 それらを使用しない実際のプログラムを作成することはほとんど不可能です(実行できる可能性がありますが、それは超メガ倒錯であり、実際のプログラムではありません!)。 誰もこれについて議論しません。
しかし、なぜ、C / C ++に集中している高級言語では、goto演算子が突然支持されなくなったのですか?..
アルゴリズムについて少し
それでは、トリッキーなアルゴリズムを見てみましょう。 これがどのようなナンセンスなのかはわかりませんが、実装する必要があります。
UPD :ここで、A、B、C、D、Eはいくつかの操作ですが、関数呼び出しではありません! 多くのローカル変数を使用する可能性があります。 そして、彼らは彼らの状態を変える可能性があります。 つまり、この場合、関数の呼び出しについては説明しません-一部のアクションは詳細になりません。
gotoを使用したCでは、次のようになります。
if (a) { A; goto L3; } L1: if (b) { L2: B; L3: C; goto L1; } else if (!c) { D; goto L2; } E;
. — ! goto:
char bf1, bf2, bf3; if (a) { A; bf1 = 1; } else bf1 = 0; bf2 = 0; do { do { if (bf3 || b) bf3 = 1; else bf3 = 0; if (bf3 || bf2) B; if (bf3 || bf1 || bf2) { C; bf1 = 0; bf2 = 1; } if (!bf3) { if (!c) { D; bf3 = 1; } else { bf3 = 0; bf2 = 0; } } } while (bf3); } while (bf2); E;
- ?..
:
- 5 , .
- goto 2 .
- goto . – , .
- ?
- , , 100%. … .
- .
goto!
, . .
goto
20- , ActiveHDL, , , ( , ). , - . , , – — , .
… , .
goto
, goto – . for (…), while (…) {…}, do {…} while (…). switch (…) {case … case …}. / break continue. , funct() return.
++ , . – try {… throw …} catch (…) {…}.
goto «» — goto?
goto
, , . . – , !
– .
– , - , . ! , ++ ? ++ («» , ): , , , , … , ++… , , – « ».
, – ? - . 220 – ! – .
goto. – .
– , , . ? – , ! , - ! , – . !
, , a = ++i , i = i + 1; a = i. , ?
, C++ , goto :
goto Label; for (;;) { int p = 0; Label: p += 10; }
p? ! , – , p .
– Visual Studio 2008.
? , - goto . , . .
++ try … throw … catch. . ++ — , . goto. , . – , , .
, goto. «» , UART, USB . .
:
char a, b, c; for (a = 0; a < 10; ++a) { for (b = 0; b < a; ++b) { if (!c) goto Leave; } for (b = 10; b < 15; ++b) { d (); } } Leave: e ();
– ? . - – .
:
char a, b, c, f1; f1 = 1; for (a = 0; a < 10 && f1; ++a) { for (b = 0; b < a && f1; ++b) { if (!c) f1 = 0; } if (f1) { for (b = 10; b < 15; ++b) { d (); } } } e ();
? . . , «» PC. – .
, ( , Java) break Leave. goto, !
switch (…) { case …}. .
UPD: , , ++. ++ «» throw… catch…. , throw… catch… — goto!
? ? , ( boost::spirit). , « » — , ; , . goto …
, ++ , . . , , goto?.. – , . . – .
- :
int f (…) { … if (a) { c = 15; return 10; } … if (b) { c = 15; return 10; } … = 10; return 5; }
:
int f (…) { … if (a) goto Exit; … if (b) goto Exit; … = 10; return 5; Exit: c = 15; return 10; }
? - . . goto. .
, …
! . – , !
, , goto .
– goto .
UPD: , goto .
goto:
- ( . . ) switch… case
- : ( )
- ,
goto:
- ( , , )
- ( )
/? , .