パスワードを忘れた? アカウント作成
11918380 story
プログラミング

C言語の開発者によるgoto文の使い方を対象とした実証研究の結果、「goto文は無害だと考えられる」 106

ストーリー by headless
無害 部門より
Edsger Dijkstra氏がgoto文の危険性を主張したのは1968年。それから50年近く経過した現在もgoto文は使われ続けているが、Dijkstra氏が懸念したようなgoto文の無制限な使用が行われているのかどうかという点や、それがバグの原因となるような有害なものなのかどうかといった点については、よくわかっていなかったという。こういった点に関する実証研究が本家/.で紹介されている。

本家/.「Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"」より

200万近いC言語のファイルと1万1千件を超えるプロジェクトからランダムに抽出した統計的に有効なサンプルを質的および量的に分析したところ、開発者はほとんどの場合gotoの使用を適切に制限しており、Dijkstra氏が懸念したような無制限な使用は行われていないことが判明した。これらのことから、実際にはgotoは有害でないものと考えられる。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • 原因と結果が逆 (スコア:5, すばらしい洞察)

    by Anonymous Coward on 2015年02月15日 13時13分 (#2761357)

    1968年の論文を踏まえて無軌道にgotoを使わなくてもいいように言語仕様が設計されたりプログラマーが使用を自重するようになったんだろ。

    • Re:原因と結果が逆 (スコア:2, すばらしい洞察)

      by Anonymous Coward on 2015年02月15日 13時42分 (#2761378)

      今となっては goto 文を使う人は、そうした方が見通しいい場合に限り使っているという印象
      case break の方が危ういね

      #一般のブロック抜けgotoが欲しい

      親コメント
      • by annoymouse coward (11178) on 2015年02月15日 18時12分 (#2761521) 日記

        > #一般のブロック抜けgotoが欲しい

        C言語だと,ブロックを別関数にして return を使う,というのが一つの解ですね.

        別関数にすると,関数呼び出しのオーバヘッドを気にする人がいますが,オーバヘッドは生じません.
        今時のコンパイラは最適化処理が賢いので,無駄な関数呼び出しは自動でインライン展開されます.

        ただ関数にするとローカル変数をすべて関数の引数として渡す必要があるので,コーディングするときは少々面倒です.

        最近のC++だともっと綺麗かつ効率良いコードが書けます.具体的には

                  std::vector<int> a = {3,5,7,13,17};
                  std::for_each(a.begin(), a.end(),
                            [](auto x){
                                      if (x>10)
                                        return;
                                      std::cout << x << std::endl;
                            });

        みたいな感じで,ブロックをラムダ式で記述して,return で抜ける,と綺麗に書けます.
        ローカル変数を渡すのも簡単です

        ですので,goto使いたくなければ,C++で書く,というのは結構良い選択肢だと思います.

        親コメント
        • その例なら、ラムダ式を使わないようにするともっときれいに書けるよ。

          std::vector<int> a = {3, 5, 7, 13, 17};
          for (int x : a) {
              if (x > 10)
                  break;
              std::cout << x << std::endl;
          }

          というか、もともと C/C++ の break だけで済むコードをわざわざラムダ式と return に書き直してくれても、何がきれいだと言いたいのかさっぱりわからないんだけど……。二重のループの外側を for_each とラムダ式で書くと、内側を抜けるのは break で、外側を抜けるのは return で書けるからきれいとか、そういう話? 僕はそういう書き方が特にきれいだとは思わないけれど。

          親コメント
          • いや、ごめんなさい、 break じゃなくて continue にしないと同じ挙動にならなかった……。ますます annoymouse coward さんが何を言いたいのかわからない。

            親コメント
        • by ktmizugaki (46208) on 2015年02月15日 22時17分 (#2761639) 日記

          う、う~ん?これは綺麗なんでしょうか。

          大分話がそれますが、Ruby の each に渡すブロック内での、break と return の挙動がどうもしっくりきません……。

          switch の case と言えば昔C言語で、クラッシュの原因を探って行ったら、break 抜けだったことがありました。

          --
          svn-init() {
            svnadmin create .svnrepo
            svn checkout file://$PWD/.svnrepo .
          }
          親コメント
      • by Anonymous Coward

        「gotoはダメだgotoはダメだgotoはだめだ」って唱えながら、
        こんなことするくらいなら、gotoのほうが遥かにまとも

        do {
                ...
                break;
                ...
        } while(0);

        • by Anonymous Coward

          ごめんなさい
          do {} while(false);多用してます…

          だってラベル名考えるのがめんど(
          流石にこれやるとき多重ループは禁止にしてますが。

          あとgoto使うと途中宣言が禁止されるのが苦手

          • by Anonymous Coward

            久しくコーディングしていないけど、do { } while(0); はマクロ書くときくらいかも

    • 直感的にそうだろうとは思っていたけど、こうしてきちっと調べて、言葉にしてもらえるといいね

    • by Anonymous Coward

      さんざgotoを悪者扱いしてきた奴の
      言い訳っぽい

    • by Anonymous Coward

      言語はCなんだから言語使用は無関係と言えるのでは?

      #ストーリーを読まなくてもすばらしい洞察。すばらしいですね。

  • goto fail; (スコア:1, 参考になる)

    by argon (3541) on 2015年02月15日 13時04分 (#2761352) 日記

    iOS7.0.6で修正された「最悪のセキュリティバグ」はありがちなコーディングミスで発生していた
    http://apple.srad.jp/story/14/02/24/094232/ [srad.jp]

    • Re:goto fail; (スコア:3, すばらしい洞察)

      by plauda (46850) on 2015年02月15日 13時33分 (#2761374)

      これをコーディングした開発チームがgoto文のせいだと結論づけるなら、
      そのチームは今後も致命的なコーディングミスを量産し続けるでしょう。

      goto文を使わなくなったとしても、ありがちなコーディングミスを
      見つけられない検証プロセスしか持たない開発チームの生産物を受け取りたくない。

      親コメント
    • by Anonymous Coward on 2015年02月15日 13時32分 (#2761373)

      goto問題じゃなくてifの使い方だろ

      親コメント
      • Re:goto fail; (スコア:2, すばらしい洞察)

        by Anonymous Coward on 2015年02月15日 14時06分 (#2761393)

        いや static変数の使い方 と 値を入れてないままの変数を返しているってのをチェックできていないというのが本質だろう。
        static変数の定義が明示的な初期化が無くても0が保証されるという仕様は、バグの元だとおもう。この仕様がため、代入前の参照が警告にもならなかったのだろうし。
        初期化子のない変数は-1などトラップされやすい値を入れるとか、デバッグ用コンパイルスイッチがあってもよさそう.

        親コメント
        • by Anonymous Coward on 2015年02月16日 12時09分 (#2761828)

          GCCなら、-fno-zero-initialized-in-bssで初期化されているものをbssから除き、リンカの設定でbssを消せばいいと思う。
          実際、私は組み込み機器向けにバイナリ形式で実行ファイルを生成するときにこのオプションを使いました。バイナリのサイズを小さくでき、bssの初期化用のコードも不要なので便利です。

          親コメント
        • by Anonymous Coward

          いや、人間の注意力を過信してるのがいけないだけ。
          if書いた後必ずブロックを開く({を書く)ようにすればバグは出ない。

  • 実のところ、goto文の乱用が危険であること、それの使いどころがどこか正しく広まっている今、
    gotoに関するバグがあったとしても、goto文がクソなのではなく、コードを設計するプログラマ(あるいは教育者)がクソなのでしょう。

    商用のプログラムで例外処理を手厚くやると、あちこち例外処理だらけになるが、
    それを共通化する手段に、例外処理専用の関数を作るか、goto文で例外処理の共通処理コードの
    どちらが適切かは、設計者がきちんとメリット・デメリットを理解しているなら、goto文を使った実装でも問題ないだろう。

    あまり良い例ではないが、フローチャートとか何も考えずに書いて、それを素直に実装すると goto文だらけになる。
    設計が駄目なら、駄目なコードになるし、そうでなければ全うなコードになる。
    (※フローチャートについて例示の一つであり、それの議論を繰り広げたい訳ではない。今は、代替の図解手法がいくらでもある。)

    • by Anonymous Coward

      「gotoは事故を招くから用心深く使いましょう」よりも
      「用心なしでは事故を招くような要素のある言語を、全てのプログラマが使わざるをえないような状況はおかしい」と考えたほうがいい気がするなあ。

      プログラミングの達人と、人間工学&ユーザビリティの達人って、求められる思考が対極にあると思う。

      • そっち側の人は、新しい言語を作るんじゃないでしょうか。
        それに言語仕様に対する論争はもう、みんな議論し尽くした感があります。

        (C言語以外の話は議論が発散するので置いておきましょう)

        今の時代、コンパイラの警告とかコードチェックツールも随分進化した点は見逃せないと思います。
        到達しないコードや未初期化の変数に対する警告など、
        (見る気があれば) タイプミスレベルならかなり高い確度で検出されるようになっています。
        (商用で超遅かったりしますが)意味チェックに近い領域までやってくれるものもありますしね。

        それでも誤りを犯すことに対して、人間工学&ユーザビリティだとか議論するなら、
        具体的なコード例などの情報がないと、ツールで検出できるものか、
        言語の問題(仕様あるいはエラーとして扱うべきものをエラーとしていない)か、
        開発プロセスの問題かを切り分けできないでしょう。

        言語仕様の改善は難しく、改善のトレンドは構文チェックツールだと思います。
        既存のプログラム言語は、過去の資産が多すぎて一律に文法を変えるとかは無理でしょう。
        それゆえ、警告を出すというのは妥当な妥協点でしょう。もし、構文を変えるなら、オプション指定で
        部分的に変更することになると思います。この場合、コンパイラのオプション指定も複雑になります。
        用心なしでコードを書くプログラマが細やかなオプション指定は難しいのではないでしょうか?

        ……というわけで、昨今のC言語のコーディングの問題について、
        人間の行動から導き出す妥当な解決手段は、大半は開発プロセス側(構文チェックをするとか)にあるんじゃないかなと思うのです。

        親コメント
  • by Anonymous Coward on 2015年02月15日 13時11分 (#2761356)

    バイナリを生成できる言語が他にないからCを使ってるだけで、
    本音の所では、正直できればC以外で書きたいプロジェクトが結構あるような気がする

    • by Anonymous Coward

      べつに下手くそなc使いより上手なJAVA使いの方がいいコード書くやろ

      • by Anonymous Coward

        下手糞なC使いとの比較は、下手糞なJava使いじゃないのか?
        目くそ鼻くそのような気がしてならない。

        下手糞なC使いは下手糞なコーディングで、テスト中にプログラムをクラッシュさせる代わり、本番はそれなりに動くが、
        下手糞なJava使いは下手糞なコーディングで、テストはそれなりにこなし、本番中にメモリリークや性能トラブルを起こすような印象がある。

        例えだが、こんな感じの印象で比較して何の意味があるかと。

        • 目くそ鼻くそな話だけど・・・

          下手糞なコーディングでも気が付きにくいのはJavaよりMS系のほうが多いけどね。
          例えば、
          ・Stringの+=の連結
           Javaはわりとすぐ遅くなるからStringBuilderを使わなきゃだめだと気がつきやすいし説得しやすいが、
           .NETなんかはStringBuilderの存在価値を見出すためにはかなりループさせなきゃならない。
          ・HashMapやDBの結果の並び順
           JavaのHashは入れた順番になんて取り出せない。Oracleの検索結果も同様。Order by忘れすぐわかる。
           .NETやSQLSERVERはほとんどの場合、入れた順に取り出せる。でも保証されてるわけじゃないから本番ある程度立ってからおかしな動きが出てくる
          MS系のばかりやってる人は例外処理についてきちんと設計できない人多い。

          レベルの低い話だけど業務系のプログラミングの現場は未だにこんなんばっか。

          親コメント
  • by duenmynoth (34577) on 2015年02月15日 13時15分 (#2761360) 日記
    で?っていう。

    コードの質なんてコーダー次第なんだし、
    いくら無作為に大量のサンプルを解析なんてしたところで、
    使い方次第な物を杓子定規で定義しても意味なんて無いよ。

    #バグの温床である事には変わりないわけだし
    • Re:机上の空論 (スコア:2, おもしろおかしい)

      by Anonymous Coward on 2015年02月15日 13時42分 (#2761377)

      if文はバグの温床だから使用禁止ね。

      親コメント
    • by Anonymous Coward

      こういう思考停止がgotoを無条件に禁止とか言い出して、余計なバグを生み出すんだなあ。

    • by Anonymous Coward

      「バグの温床であるという事」

      「コーダー次第」
      である事を今回研究しましたよ、って事なんじゃねーの。

      もっとも、そんなの20年以上前から言われてるんだけどね。
      規約を宗教化する人が原理主義に突き進んだ面が大きい。

  • by Anonymous Coward on 2015年02月15日 14時35分 (#2761404)

    当時はひどかった

    • by Anonymous Coward

      あと他の言語でも調べてみて欲しいですね。BASIC,DOSみたいなMS系を

      • MS設立は75年らしいですね。
        私はN-BASIC使ったことがありまして、それはもう飛ばしまくっておりました。(^^;
        当時FDDはとてつもなく高価で断念。純正プリンタも無理。

        前後して、高校のときFx-501Pをおもちゃにしてました。
        仕事に付いて(その当時)関数機能付電卓が必須でFx-501Pは重宝してましたが
        いかんせん128ステップ、限界が見えてきてPC-1245を購入。ここでN-BASICの
        悪夢が蘇る。その後PC-1245の後継機種を購入して満開…

        i386ノートを購入してQuickBASICをN-BASICのノリで… だって数値計算だし(^^;
        構造化は以前から聞いてたんですよ。ただ、俺には関係ねぇ~ の世界。
        で、TurboPASCAL6.0を使ったんです。慣れるに相当掛かりましたが、それで
        大人しくなりました。それまでK&R(2版)何言ってるか分からなかったのですが、
        TP使うようになって普通に読めるようになった。

        今は殆んど書いていませんが、正邪どちらも書けると…

        #西の国へ旅立つ前に、デバイスドライバをなんとかしたい。
        #また邪の世界に身を投じても、それも良いかなと…

        親コメント
      • by Anonymous Coward

        DOSって何だ? .BAT の文法こと?
        それはともかく、例えばFORTRAN IV (でも水準7000でもいいから)あたりで分析しないと意味無いよね。

      • by Anonymous Coward

        68年には当然彼の国民機もまだ存在していなかったし、8080さえできてないんじゃないのか。

  • by Anonymous Coward on 2015年02月15日 15時11分 (#2761421)

    後藤文ちゃんと、はじめてのCしても問題ないよねっ

  • by Anonymous Coward on 2015年02月15日 15時20分 (#2761429)

    天然痘での死者が出ていないからCDCに保管されてる天然痘ウィルスは無害だった、って主張だよね。

  • by Anonymous Coward on 2015年02月15日 16時07分 (#2761445)

    コードに行番号がなくて、いちいちラベルとかつけなきゃいけないから
    GOTOが使いにくい。
    もっとBASICを見習ってほしい(Visual BASICはダメだよ)。

typodupeerror

あつくて寝られない時はhackしろ! 386BSD(98)はそうやってつくられましたよ? -- あるハッカー

読み込み中...