web-dev-qa-db-ja.com

一部のカーネルプログラマーが単純なwhileループの代わりにgotoを使用するのはなぜですか?

私がCを学んだとき、先生は一日中私に言った:「gotoを使用しないでください、それは悪い習慣です、それは醜く、危険です!」等々。

それでは、なぜ一部のカーネルプログラマはgotoを使用するのでしょうか。たとえば、 この関数では を使用します。

while(condition) {} 

または

do {} while(condition);

理解できません。場合によっては、while/do-whileの代わりにgotoを使用する方が良いですか?もしそうなら、なぜですか?

52
musicmatze

この例の場合、それはSMPサポートを元々SMPセーフでない方法で記述されたコードに改造することに関するものだと思います。 goto again;パスを追加することは、関数を再構築するよりもはるかに単純で侵襲性が低くなります。

私はこのスタイルが好きだとは言えませんが、イデオロギー上の理由からgotoを避けるのは見当違いだと思います。 gotoの使用法の特殊なケースの1つ(この例とは異なります)は、gotoが関数内で前方に移動するためにのみ使用され、後方には使用されない場合です。このクラスの使用法では、gotoからループ構造が発生することはなく、ほとんどの場合、必要な動作を実装するための最も単純で明確な方法です(通常、クリーンアップしてエラーが返されます)。

28
R..

歴史的文脈:ダイクストラがGotoは有害と見なされるを書いたことを覚えておく必要があります1968年、多くのプログラマがgoto構造化プログラミングifwhileforなどの代わりに使用しました。 。)。

それは44年後のことであり、このようなgotoの使用が実際に見つかることはまれです。構造化プログラミングは、はるか昔にすでに勝利しています。

ケース分析:

コード例は次のようになります。

    SETUP...
again:
    COMPUTE SOME VALUES...
    if (cmpxchg64(ptr, old_val, val) != old_val)
        goto again;

構造化バージョンは次のようになります。

SETUP...
do {
    COMPUTE SOME VALUES...
} while (cmpxchg64(ptr, old_val, val) != old_val);

構造化バージョンを見ると、「ループだ」とすぐに思います。 gotoバージョンを見ると、「再試行」ケースが最後にある直線と考えることができます。

gotoバージョンでは、同じ列にSETUPCOMPUTE SOME VALUESの両方があり、ほとんどの場合、制御フローは両方を通過します。構造化バージョンは、SETUPCOMPUTE SOME VALUESを異なる列に配置します。これは、コントロールがそれらを別々に通過する可能性があることを強調しています。

ここでの質問は、コードにどのような強調をしたいですか?エラー処理のためにこれをgotoと比較できます。

構造化バージョン:

if (do_something() != ERR) {
    if (do_something2() != ERR) {
        if (do_something3() != ERR) {
            if (do_something4() != ERR) {
                ...

後藤バージョン:

if (do_something() == ERR)  // Straight line
    goto error;             // |
if (do_something2() == ERR) // |
    goto error;             // |
if (do_something3() == ERR) // |
    goto error;             // V
if (do_something4() == ERR) // emphasizes normal control flow
    goto error;

生成されたコードは基本的に同じなので、インデントのような表記上の問題と考えることができます。

56
Dietrich Epp