このスレッドでは、CまたはC++でのgoto
の適切な使用例を見ていきます。それは 回答 に触発されたものです。
概要(意図をより明確にするためにラベルをオリジナルから変更):
_infinite_loop:
// code goes here
goto infinite_loop;
_
他の選択肢よりも優れている理由:
goto
は、無条件分岐を引き起こす言語構成体です。代替案は、条件付き分岐をサポートする構造の使用に依存しており、退化した常に真の条件です。break
sの間に介在するコードをスキャンする必要はありません(ただし、未熟なハッカーがcontinue
を初期のgoto
でシミュレートすることは可能です)。ルール:
大人のようにこれについて話すことができるかどうか見てみましょう。
編集
この質問は終了したようです。質の高い回答が生成されました。みんな、特に私の小さなループの例を真剣に考えてくれた人たちに感謝します。ほとんどの懐疑論者は、ブロックスコープの欠如に懸念を抱いていました。 @quinmarsがコメントで指摘したように、ループ本体の周りにいつでも中括弧を置くことができます。 for(;;)
とwhile(true)
はどちらも無料で中括弧を与えないことに注意してください(それらを省略すると厄介なバグが発生する可能性があります)。とにかく、私はこの些細なことであなたの脳力をこれ以上浪費しません-私は無害で慣用的なfor(;;)
とwhile(true)
で生きることができますジョブ)。
他の応答を考えると、多くの人がgoto
を常に別の方法で書き直さなければならないものと見なしていることがわかります。もちろん、ループ、余分なフラグ、ネストされたgoto
sのスタックなどを導入することでif
を回避できますが、goto
がおそらく最良かどうかを考慮しないでください。仕事のためのツール?別の言い方をすれば、組み込みの言語機能を意図した目的に使用することを避けるために、人々はどれだけさを我慢しているのでしょうか?私の考えでは、フラグを追加しても高すぎて支払うことができないということです。私は自分の変数が問題や解決策の領域にあるものを表すのが好きです。 「goto
を避けるためだけに」はカットしません。
クリーンアップブロックに分岐するためのCパターンを与えた最初の回答を受け入れます。 IMO、これは投稿されたすべての回答のgoto
に対して最も強力なケースになります。確かに、嫌いな人がそれを避けるために通過しなければならないゆがみによってそれを測定するなら。
人々が使用していると聞いたことがあります。私は野生でそれを見たことがありません。また、C++にはこれをより慣用的に行うRAIIがあるため、Cにのみ適用されます。
void foo()
{
if (!doA())
goto exit;
if (!doB())
goto cleanupA;
if (!doC())
goto cleanupB;
/* everything has succeeded */
return;
cleanupB:
undoB();
cleanupA:
undoA();
exit:
return;
}
CでのGOTOの典型的なニーズは次のとおりです。
for ...
for ...
if(breakout_condition)
goto final;
final:
Gotoなしでネストされたループを抜け出す簡単な方法はありません。
以下は、シグナルによって中断される可能性のあるUnixシステムコール用の私の愚かな例です(Stevens APITUEから)。
restart:
if (system_call() == -1) {
if (errno == EINTR) goto restart;
// handle real errors
}
代替手段は縮退ループです。このバージョンは、「システムコールがシグナルによって中断された場合、それを再起動する」英語のように読みます。
Duffのデバイスがgotoを必要としない場合、どちらも必要ありません! ;)
void dsend(int count) {
int n;
if (!count) return;
n = (count + 7) / 8;
switch (count % 8) {
case 0: do { puts("case 0");
case 7: puts("case 7");
case 6: puts("case 6");
case 5: puts("case 5");
case 4: puts("case 4");
case 3: puts("case 3");
case 2: puts("case 2");
case 1: puts("case 1");
} while (--n > 0);
}
}
wikipediaの上記のコード entry 。
Knuthは「GOTOステートメントを使用した構造化プログラミング」という論文を書いています。 from here 。そこには多くの例があります。
ごく普通。
_do_stuff(thingy) {
lock(thingy);
foo;
if (foo failed) {
status = -EFOO;
goto OUT;
}
bar;
if (bar failed) {
status = -EBAR;
goto OUT;
}
do_stuff_to(thingy);
OUT:
unlock(thingy);
return status;
}
_
私がgoto
を使用する唯一のケースは、通常はブロックから飛び出し、決してブロックに飛び込むことではありません。これにより、do{}while(0)
およびネストを増やすその他の構成要素の悪用を回避しながら、読み取り可能な構造化コードを維持します。
私は一般的にgotoに反対することはありませんが、あなたが言及したようなループにそれらを使用したくないいくつかの理由を考えることができます:
Gotoを使用するのに適した場所の1つは、いくつかのポイントで中断できるプロシージャです。各ポイントでは、さまざまなレベルのクリーンアップが必要です。 Gotophobesは、gotoを構造化コードと一連のテストで常に置き換えることができますが、過剰なインデントを排除するため、これはより簡単だと思います。
if(!openDataFile()) goto quit; if(!getDataFromFile()) goto closeFileAndQuit; if(!allocateSomeResources) goto freeResourcesAndQuit; //ここでさらに作業を行います。.. freeResourcesAndQuit: //空きリソース closeFileAndQuit: //ファイルを閉じる quit: //終了!
@ fizzer.myopenid.com:投稿されたコードスニペットは以下と同等です。
while (system_call() == -1)
{
if (errno != EINTR)
{
// handle real errors
break;
}
}
私は間違いなくこの形式を好む。
時間が経つにつれてこのパターンを嫌うようになりましたが、それはCOMプログラミングに組み込まれています。
#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
HRESULT hr = S_OK;
IfFailGo( pFoo->PerformAction() );
IfFailGo( pFoo->SomeOtherAction() );
Error:
return hr;
}
良いgotoの例を次に示します。
// No Code
Gotoが正しく使用されているのを見てきましたが、状況は通常見苦しいです。 goto
自体の使用が元のものよりもずっと悪い場合にのみです。 @Johnathon Hollandの問題は、あなたはバージョンがあまり明確ではないということです。人々はローカル変数が怖いようです:
_void foo()
{
bool doAsuccess = doA();
bool doBsuccess = doAsuccess && doB();
bool doCsuccess = doBsuccess && doC();
if (!doCsuccess)
{
if (doBsuccess)
undoB();
if (doAsuccess)
undoA();
}
}
_
そして、私はこのようなループを好むが、一部の人々はwhile(true)
を好む。
_for (;;)
{
//code goes here
}
_
これに関する私の不満は、ブロックスコープを失うことです。 gotoの間に宣言されたローカル変数は、ループが破壊された場合でも有効です。 (たぶんあなたはループが永遠に実行されると仮定している;私はそれが元の質問作家が尋ねていたとは思わない。)
一部のオブジェクトは、適切なタイミングで呼び出されるdtorに依存している可能性があるため、スコープの問題はC++の問題です。
私にとって、gotoを使用する最良の理由は、マルチステップの初期化プロセス中です。このプロセスでは、失敗した場合にすべてのinitをバックアウトすることが不可欠です。
if(!foo_init())
goto bye;
if(!bar_init())
goto foo_bye;
if(!xyzzy_init())
goto bar_bye;
return TRUE;
bar_bye:
bar_terminate();
foo_bye:
foo_terminate();
bye:
return FALSE;
#include <stdio.h>
#include <string.h>
int main()
{
char name[64];
char url[80]; /*The final url name with http://www..com*/
char *pName;
int x;
pName = name;
INPUT:
printf("\nWrite the name of a web page (Without www, http, .com) ");
gets(name);
for(x=0;x<=(strlen(name));x++)
if(*(pName+0) == '\0' || *(pName+x) == ' ')
{
printf("Name blank or with spaces!");
getch();
system("cls");
goto INPUT;
}
strcpy(url,"http://www.");
strcat(url,name);
strcat(url,".com");
printf("%s",url);
return(0);
}
私自身はgotoを使用していませんが、特定のケースでgotoを使用することがある人と一緒に仕事をしました。私の記憶が正しければ、彼の理論的根拠はパフォーマンスの問題に関するものでした-彼はまた、howのための特定のルールを持っていました。常に同じ機能であり、ラベルは常にgotoステートメントの下にあります。