2009-05-25 7 views
7
私はちょうど冗長ジャバー:)とにかく
ようにあなたには思えない、次を願っ

、それがあります:スタイルの質問は

for (p = fmt; *p; p++) { 
    if (*p != '%') { 
     putchar(*p); 
     continue; 
    } 
    switch (*++p) { 
     /* Some cases here */ 
     ... 
    } 
} 

そして私はなぜ疑問に思いました作家(Kernighan/Ritchie)はifの文でcontinueを使用しました。
私はそれがelseの文の下にswitch全体をくぼませるよりもエレガントだと思ったのは単なる理由だと思いましたが、どう思いますか?完全に有効になります

elseステートメント内のスイッチ全体を置く -

答えて

15

おそらく。人間の脳はスタック空間が限られており、深く入れ子構造に対処することは困難です。私たちが解析すると予想される情報を平らにするものは、理解しやすくなります。これに

bool foo(int arg) 
{ 
    if(!arg) { 
     /* arg can't be 0 */ 
     return false; 
    } else { 
     /* Do some work */ 
     return true; 
    } 
} 

か悪いか、::ない最後の例では

bool foo(int arg) 
{ 
    if(arg) { 
     /* Do some work */ 
     return true; 
    } else { 
     /* arg can't be 0 */ 
     return false; 
    } 
} 

、一部これに

bool foo(int arg) 
{ 
    if(!arg) { 
     /* arg can't be 0 */ 
     return false; 
    } 

    /* Do some work */ 
    return true; 
} 

同様に、私は通常これを好みます仕事はかなり長いかもしれません。読者がelse節に達する時までに、彼はそこにどのように辿り着いたのか覚えていないかもしれません。

ベールアウトの条件を最初に近づけておくと、関数を呼び出そうとする人に、関数の入力がどのような入力を期待しているかがわかります。

また、他の人も指摘しているように、ループ内のコードをさらに読む必要がないため、コードの後に​​処理が追加されるかどうかを判断する必要はない。繰り返しますが、あなたが読者に追いつかせることを少なくするほど、良いことです。

1

は、このようなコードを書くために、常に多くの方法があります。私は彼らがこのようにした理由は、当時思った通りだったと思うでしょう:

"pの値が '%'と等しくない場合、

elseでスイッチすると、その特定のケースで次の繰り返しにジャンプしたことが作者にはっきりと分かっていない可能性があります。

これは完全に個人的な選択です。私はあまり心配しません - あなたとあなたのチームに最も合った方法でそれを書いてください。

1

私は同意します。 しかし、それを「単なる理由」と見ることはできません。実際には、コードのすべての複雑さを軽減するため、実際にはかなり良い理由です。それを短くて読みやすく理解しやすくする。

2

このように置いたほうが読みやすくなります。

ここでループを通したこの繰り返しで完了しましたか?はい?したがって、を次の繰り返しでに進めるようにしてください。あなたはelseニーズがインデントされる内elseそして、すべてのものを使用している場合

+1

それは、このイディオムがあなたのコードで共通であるかどうかによって異なります。そうでなければ、ループを制御するやや珍しい方法であるという欠点と潜在的なメンテナンスの問題/バグの原因があります。 –

+0

はい、それはかなり正しいです。このイディオムに慣れていない人々は、それを維持することに直面すると混乱するかもしれません。それは私が慣れてきたものであり、私に教えたヒューリスティックが優れています。ネストされたif-then-elseブロックで迷子になってしまい、休憩に気づくのは簡単です。または続行する。 –

1

if() 
{ 
    doA() 
    continue; 
} 
doB(); 
if() 
{ 
    doC(); 
    continue; 
} 
doD(); 

また、continue手段:あなたはcontinueを使用している場合

if() 
{ 
    doA(); 
} 
else 
{ 
    doB(); 
    if() 
    { 
    doC(); 
    } 
    else 
    { 
    doD() 
    } 
} 

は、あなたはインデントする必要はありません。そのケースについて考えるのをやめることができます。たとえば、elseと表示された場合は、後で'%'ケースの処理がループの後半、つまりの最後にあります声明;一方、continueを見ると、ループ内のケースが完全に終了したことがわかります。

1

最も可能性の高い理由は、後に続くswitchがかなり長いことです。これは、printf形式の解析のようです。

2

私は彼がスイッチの下でコードをインデントするのに十分な理由があると思うし、機能の肉全体をインデントすることは、水平方向のスペースをかなり無駄にしています。コードが書かれた時点で、私は80文字の幅がまだ普及していたと思います。

私は理解するのが難しいとは思わないが、すぐにやっていないこと、そしてGTFOについて言及するのはかなりいいと思う。

9

このループ反復のためにコードが完了していることは、継続して明らかです。 elseが使用されている場合は、elseの後にコードがないかどうかをチェックする必要があります。

私はできるだけ早くコンテキストを終了するのが良い習慣であると思うので、これははるかに明確なコードにつながります。例えば


if(arg1 == NULL) 
    return; 

if(arg2 == NULL) 
    return; 

//Do some stuff 

if(arg1 != null) 
{ 
    if(arg2 != null) 
    { 
    //Do some stuff 
    } 
} 
+1

+1コードをクリアしてください。これに加えて、コードが後で修正されたときには、上で処理されたため、すべてのエラーケースについて考える必要はありません。有効なケースのみを処理する必要があることは分かっています。このようにしてコードを書くことは非常にエレガントだと感じます。他のバージョンの経験があり、他の会社の標準でもありました。唯一のリターンスタッフ... – stefanB

1

ループを破る/継続するために、よりその1つの理由があるかもしれません。だから、次回になります

loop 
{ 
    if (cond1) 
     continue; 
    if (cond2) 
     continue; 
    if (cond2) 
     continue; 
    if(more conditions...) 
     continue; 

    the loop action 
} 

そして、あなたも、「すべてのすべての構造を理解する必要はありません。

loop 
{ 
    if (cond1) 
    { 
     if (cond2) 
     { 
     if (cond2) 
     { 
      more conditions... 
     } 
     } 
    } 
    else 
    { 
     the loop action 
    } 
} 

を私見それはとてもエレガントで、あなたの例では、ループ、例えば読み取り可能ではありませんもしループ論理を理解するのがもっと複​​雑なのであれば。

P.S.ちょうどケースのために:私は著者がこのループを書く方法を考えなかったと思う、彼らはそれを書いた:)

-2

まあ、私は約11年間のCプログラムを書いたと私は5回それを理解するコード!

カーニハンとリッチーは、60年代に活動していました。当時、コードを理解することは関係がありませんでした。 16 Koに収まるコードを書くことができました。

私は驚いていません。あなたのteatchersがK & Rであるとき、Cはひどい言語です。reallocを見てください:誰が今日のようなコードを知っていますか?私は60年代、すべての激怒でしたが、少なくとも今は面白いです:o)

+2

K&Rは1960年代ではなく、1978年に登場し、一般的には非常に優れた文章、簡潔、よく書かれたものとみなされています。コードの明瞭性は非常に重要であり、1968年のNATOソフトウェア・エンジニアリング・カンファレンスでは10年前に、ソフトウェアは非常に複雑になり、「ソフトウェア危機」が発生していたことに同意した。議論されているコードサンプルは、非常に一般的なC(およびC++)イディオムを使用しています。 –

+0

さて、reallocを見てください。今日の基準では本当にうんざりです。あなたがKとRが好きなら、クール、あなたはわずか20年後です! すべてベスト! – SRO

0

私はDijkstraの教えに固執します:gotoは有害なです。そして、継続/休憩は、gotoの弟です。

問題がコードをあまりにもインデントしている場合、解決策はループ内で継続を続けるのではなく、異なる機能でコードを分離することによって複雑さを軽減するか、

例えば、@Kamareyスニペットは、このようにも明確に次のようになります。通常、私は見つけることができませんが、簡単に言うと

bool foo(int arg) 
{ 
    if(arg) { 
     /*do some work*/ 
    } 

    return arg != 0; 
} 

loop 
{ 
    if (!(cond1 || 
     cond2 || 
     cond2 || 
     ...)) 
    { 
     the loop actions; 
    } 
} 

または@Ori Pessachの例は以下のように表すことができ(非常に制限された状況でいくつかのクリーンアップコードのために多分)非構造化プログラミングコンストラクトを使用するのに十分な理由です。

+0

私はあなたの言うことを尊重します。私はDijkstraがGOTOの使用に異議を唱えたことを知っていますが、彼は継続/休憩については何も言いませんでしたか? これらのステートメントはコードを単純化することがわかりました。 –

+0

私はそれを理解しているので、E.D. _任意の_ GOTOに反対します。 continue/breakは、ターゲットができることにかなり制限されています。一方、GOTOは潜在的にどこでも行くことができます。 – mlp