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"」より
本家/.「Empirical Study On How C Devs Use Goto In Practice Says "Not Harmful"」より
200万近いC言語のファイルと1万1千件を超えるプロジェクトからランダムに抽出した統計的に有効なサンプルを質的および量的に分析したところ、開発者はほとんどの場合gotoの使用を適切に制限しており、Dijkstra氏が懸念したような無制限な使用は行われていないことが判明した。これらのことから、実際にはgotoは有害でないものと考えられる。
原因と結果が逆 (スコア:5, すばらしい洞察)
1968年の論文を踏まえて無軌道にgotoを使わなくてもいいように言語仕様が設計されたりプログラマーが使用を自重するようになったんだろ。
Re:原因と結果が逆 (スコア:2, すばらしい洞察)
今となっては goto 文を使う人は、そうした方が見通しいい場合に限り使っているという印象
case break の方が危ういね
#一般のブロック抜けgotoが欲しい
Re:原因と結果が逆 (スコア:3, 興味深い)
> #一般のブロック抜け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++で書く,というのは結構良い選択肢だと思います.
Re:原因と結果が逆 (スコア:3)
その例なら、ラムダ式を使わないようにするともっときれいに書けるよ。
というか、もともと C/C++ の break だけで済むコードをわざわざラムダ式と return に書き直してくれても、何がきれいだと言いたいのかさっぱりわからないんだけど……。二重のループの外側を for_each とラムダ式で書くと、内側を抜けるのは break で、外側を抜けるのは return で書けるからきれいとか、そういう話? 僕はそういう書き方が特にきれいだとは思わないけれど。
Re:原因と結果が逆 (スコア:2)
いや、ごめんなさい、 break じゃなくて continue にしないと同じ挙動にならなかった……。ますます annoymouse coward さんが何を言いたいのかわからない。
Re:原因と結果が逆 (スコア:2)
うーん、なるほど、 return で脱出するだけのためにラムダ式を作ってすぐ呼ぶということか。
二重のループから脱出したい、でも名前の付いた関数として分割するほどまとまった処理でもない、という場合に、その書き方は個人的には無駄に複雑な方法に見えるなあ。チーム内の取り決めとかでそういう書き方をすることになっていたら仕方ないけれど、そういう事情がなければ goto の方が数段マシな気がする。
Re:原因と結果が逆 (スコア:2)
スラッシュドットには <ecode> という謎要素があって、それを使うと不等号とかもよしなに扱ってくれるので、 C++ とかのコードをコメントとして書く場合にはお勧め。
Re:原因と結果が逆 (スコア:2)
例が適切でないだけかもしれないと思って趣旨を汲もうとした結果が、
なんだけど……。
Re:原因と結果が逆 (スコア:1)
う、う~ん?これは綺麗なんでしょうか。
大分話がそれますが、Ruby の each に渡すブロック内での、break と return の挙動がどうもしっくりきません……。
switch の case と言えば昔C言語で、クラッシュの原因を探って行ったら、break 抜けだったことがありました。
svn-init() {
svnadmin create .svnrepo
svn checkout file://$PWD/.svnrepo .
}
Re: (スコア:0)
「gotoはダメだgotoはダメだgotoはだめだ」って唱えながら、
こんなことするくらいなら、gotoのほうが遥かにまとも
do {
...
break;
...
} while(0);
Re: (スコア:0)
ごめんなさい
do {} while(false);多用してます…
だってラベル名考えるのがめんど(
流石にこれやるとき多重ループは禁止にしてますが。
あとgoto使うと途中宣言が禁止されるのが苦手
Re: (スコア:0)
久しくコーディングしていないけど、do { } while(0); はマクロ書くときくらいかも
あつものに懲りて膾を吹く (スコア:0)
直感的にそうだろうとは思っていたけど、こうしてきちっと調べて、言葉にしてもらえるといいね
Re: (スコア:0)
さんざgotoを悪者扱いしてきた奴の
言い訳っぽい
Re: (スコア:0)
言語はCなんだから言語使用は無関係と言えるのでは?
#ストーリーを読まなくてもすばらしい洞察。すばらしいですね。
Re:原因と結果が逆 (スコア:2)
E. ダイクストラのGo To Statement Considered Harmfulは1968年、C言語の誕生は1972年、仕様化はさらにその後ですから、「無関係と言える」と言えるかどうかは分かりません。
goto fail; (スコア:1, 参考になる)
iOS7.0.6で修正された「最悪のセキュリティバグ」はありがちなコーディングミスで発生していた
http://apple.srad.jp/story/14/02/24/094232/ [srad.jp]
Re:goto fail; (スコア:3, すばらしい洞察)
これをコーディングした開発チームがgoto文のせいだと結論づけるなら、
そのチームは今後も致命的なコーディングミスを量産し続けるでしょう。
goto文を使わなくなったとしても、ありがちなコーディングミスを
見つけられない検証プロセスしか持たない開発チームの生産物を受け取りたくない。
Re:goto fail; (スコア:1)
goto問題じゃなくてifの使い方だろ
Re:goto fail; (スコア:2, すばらしい洞察)
いや static変数の使い方 と 値を入れてないままの変数を返しているってのをチェックできていないというのが本質だろう。
static変数の定義が明示的な初期化が無くても0が保証されるという仕様は、バグの元だとおもう。この仕様がため、代入前の参照が警告にもならなかったのだろうし。
初期化子のない変数は-1などトラップされやすい値を入れるとか、デバッグ用コンパイルスイッチがあってもよさそう.
Re:goto fail; (スコア:1)
GCCなら、-fno-zero-initialized-in-bssで初期化されているものをbssから除き、リンカの設定でbssを消せばいいと思う。
実際、私は組み込み機器向けにバイナリ形式で実行ファイルを生成するときにこのオプションを使いました。バイナリのサイズを小さくでき、bssの初期化用のコードも不要なので便利です。
Re: (スコア:0)
いや、人間の注意力を過信してるのがいけないだけ。
if書いた後必ずブロックを開く({を書く)ようにすればバグは出ない。
正しいコーディングスタイルが広まった今、罪なのは設計であってgoto文せいではない (スコア:1)
実のところ、goto文の乱用が危険であること、それの使いどころがどこか正しく広まっている今、
gotoに関するバグがあったとしても、goto文がクソなのではなく、コードを設計するプログラマ(あるいは教育者)がクソなのでしょう。
商用のプログラムで例外処理を手厚くやると、あちこち例外処理だらけになるが、
それを共通化する手段に、例外処理専用の関数を作るか、goto文で例外処理の共通処理コードの
どちらが適切かは、設計者がきちんとメリット・デメリットを理解しているなら、goto文を使った実装でも問題ないだろう。
あまり良い例ではないが、フローチャートとか何も考えずに書いて、それを素直に実装すると goto文だらけになる。
設計が駄目なら、駄目なコードになるし、そうでなければ全うなコードになる。
(※フローチャートについて例示の一つであり、それの議論を繰り広げたい訳ではない。今は、代替の図解手法がいくらでもある。)
Re: (スコア:0)
「gotoは事故を招くから用心深く使いましょう」よりも
「用心なしでは事故を招くような要素のある言語を、全てのプログラマが使わざるをえないような状況はおかしい」と考えたほうがいい気がするなあ。
プログラミングの達人と、人間工学&ユーザビリティの達人って、求められる思考が対極にあると思う。
Re:正しいコーディングスタイルが広まった今、罪なのは設計であってgoto文せいではない (スコア:1)
そっち側の人は、新しい言語を作るんじゃないでしょうか。
それに言語仕様に対する論争はもう、みんな議論し尽くした感があります。
(C言語以外の話は議論が発散するので置いておきましょう)
今の時代、コンパイラの警告とかコードチェックツールも随分進化した点は見逃せないと思います。
到達しないコードや未初期化の変数に対する警告など、
(見る気があれば) タイプミスレベルならかなり高い確度で検出されるようになっています。
(商用で超遅かったりしますが)意味チェックに近い領域までやってくれるものもありますしね。
それでも誤りを犯すことに対して、人間工学&ユーザビリティだとか議論するなら、
具体的なコード例などの情報がないと、ツールで検出できるものか、
言語の問題(仕様あるいはエラーとして扱うべきものをエラーとしていない)か、
開発プロセスの問題かを切り分けできないでしょう。
言語仕様の改善は難しく、改善のトレンドは構文チェックツールだと思います。
既存のプログラム言語は、過去の資産が多すぎて一律に文法を変えるとかは無理でしょう。
それゆえ、警告を出すというのは妥当な妥協点でしょう。もし、構文を変えるなら、オプション指定で
部分的に変更することになると思います。この場合、コンパイラのオプション指定も複雑になります。
用心なしでコードを書くプログラマが細やかなオプション指定は難しいのではないでしょうか?
……というわけで、昨今のC言語のコーディングの問題について、
人間の行動から導き出す妥当な解決手段は、大半は開発プロセス側(構文チェックをするとか)にあるんじゃないかなと思うのです。
そもそも、なんでもかんでも無制限にCを使わない (スコア:0)
バイナリを生成できる言語が他にないからCを使ってるだけで、
本音の所では、正直できればC以外で書きたいプロジェクトが結構あるような気がする
Re: (スコア:0)
べつに下手くそなc使いより上手なJAVA使いの方がいいコード書くやろ
Re: (スコア:0)
下手糞なC使いとの比較は、下手糞なJava使いじゃないのか?
目くそ鼻くそのような気がしてならない。
下手糞なC使いは下手糞なコーディングで、テスト中にプログラムをクラッシュさせる代わり、本番はそれなりに動くが、
下手糞なJava使いは下手糞なコーディングで、テストはそれなりにこなし、本番中にメモリリークや性能トラブルを起こすような印象がある。
例えだが、こんな感じの印象で比較して何の意味があるかと。
Re:そもそも、なんでもかんでも無制限にCを使わない (スコア:2)
目くそ鼻くそな話だけど・・・
下手糞なコーディングでも気が付きにくいのはJavaよりMS系のほうが多いけどね。
例えば、
・Stringの+=の連結
Javaはわりとすぐ遅くなるからStringBuilderを使わなきゃだめだと気がつきやすいし説得しやすいが、
.NETなんかはStringBuilderの存在価値を見出すためにはかなりループさせなきゃならない。
・HashMapやDBの結果の並び順
JavaのHashは入れた順番になんて取り出せない。Oracleの検索結果も同様。Order by忘れすぐわかる。
.NETやSQLSERVERはほとんどの場合、入れた順に取り出せる。でも保証されてるわけじゃないから本番ある程度立ってからおかしな動きが出てくる
MS系のばかりやってる人は例外処理についてきちんと設計できない人多い。
レベルの低い話だけど業務系のプログラミングの現場は未だにこんなんばっか。
Re:そもそも、なんでもかんでも無制限にCを使わない (スコア:2)
+じゃなくて
+=の話し。
+はコンパイラがstringbuilderにしてくれる
机上の空論 (スコア:0)
コードの質なんてコーダー次第なんだし、
いくら無作為に大量のサンプルを解析なんてしたところで、
使い方次第な物を杓子定規で定義しても意味なんて無いよ。
#バグの温床である事には変わりないわけだし
Re:机上の空論 (スコア:2, おもしろおかしい)
if文はバグの温床だから使用禁止ね。
Re:ヘーゲル・マルクス的止揚 (スコア:1)
すずめの例は、「だから米作をやめろ」まで言わないと
ただの真な文というだけだと思う。
Re:ヘーゲル・マルクス的止揚 (スコア:1)
(#2761466) だけど、どこを比喩しているのかの理解が違っているのでその解釈だとおもう。
(#2761489) の「すずめの例は、「だから米作をやめろ」まで言わないと」を解釈すると、
プログラミングは問題の包括的な解決法だとみなされているように思われる。
一方、(#2761466) は「米作」にたとえられる、一般化された問題に対して、
さまざまな手段による解決法が行われるが、
プログラミングはその一手段でしかない、という意味で「米作におけるすずめの役割」と「プログラミングの役割」を対比させた。
その点では、「すずめ=害虫喰い」なので、プログラミングよりもバグだしに比喩させたほうが、よりよかったかもしれない。
これは反省。
以上を総括すると、私はまだまだ私の課業であるプログラミングが社会に与える影響について、過剰評価をしていた、すなわち自意識過剰、と断じられます。
おまえら、おれを殴れ!
(以上、ここまでがヘーゲル・マルクス的止揚)
Re:机上の空論 (スコア:1)
Re: (スコア:0)
こういう思考停止がgotoを無条件に禁止とか言い出して、余計なバグを生み出すんだなあ。
Re: (スコア:0)
「バグの温床であるという事」
が
「コーダー次第」
である事を今回研究しましたよ、って事なんじゃねーの。
もっとも、そんなの20年以上前から言われてるんだけどね。
規約を宗教化する人が原理主義に突き進んだ面が大きい。
68年ごろのソースを分析しろよ (スコア:0)
当時はひどかった
Re: (スコア:0)
あと他の言語でも調べてみて欲しいですね。BASIC,DOSみたいなMS系を
Re:68年ごろのソースを分析しろよ (スコア:1)
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使うようになって普通に読めるようになった。
今は殆んど書いていませんが、正邪どちらも書けると…
#西の国へ旅立つ前に、デバイスドライバをなんとかしたい。
#また邪の世界に身を投じても、それも良いかなと…
Re: (スコア:0)
DOSって何だ? .BAT の文法こと?
それはともかく、例えばFORTRAN IV (でも水準7000でもいいから)あたりで分析しないと意味無いよね。
Re: (スコア:0)
68年には当然彼の国民機もまだ存在していなかったし、8080さえできてないんじゃないのか。
Re:68年ごろのソースを分析しろよ (スコア:2)
これはちょっと同意しかねるなあ。動作原理は一緒だとしても、バイナリーコードも違えば可用性や保守体制、そもそも使用目的からして全然違うのだから。「マイコンはミニコンを1チップにしたもの」のほうがまだ納得できる。
---- 6809
萌え擬人化 (スコア:0)
後藤文ちゃんと、はじめてのCしても問題ないよねっ
悪いのはgoto文ではないんです (スコア:1)
『綺麗なコーディング規約とジョルト・コーラで育てたコードのgoto文は不具合を吐かないことがわかったんです』
『あんなに大きかったビジネスロジックのコードがこんなに小さくなるとは想像したこともなかった』
シリコンの谷のなんとか、ですね。
ちょっと意味がわかりません (スコア:0)
天然痘での死者が出ていないからCDCに保管されてる天然痘ウィルスは無害だった、って主張だよね。
Re:ちょっと意味がわかりません (スコア:1)
包丁の使い方を調査したところ、99%は適切に使用されている。
ということでしょ。
Re: (スコア:0)
全然違います
Cは (スコア:0)
コードに行番号がなくて、いちいちラベルとかつけなきゃいけないから
GOTOが使いにくい。
もっとBASICを見習ってほしい(Visual BASICはダメだよ)。
Re:GOTOを待ちながら (スコア:1)
ラッキーちゃんなんですね。