C言語の設計ミスった危険な関数トップ10決めようぜ
バッファオーバーフローしないデータを食わせれば良い わざわざ変なデータを入力するヤツが悪い って考えの時代の関数だ gets は、もう、標準ライブラリにも入っていないので許せ >>36 1行80文字とかって決め打ちできる環境なんでしょ 自分しか使わないようなツールとかならこれで十分 って考え 8ビットの整数型を char などというものにしたのも、アメリカ人は 自分たちの英語しか知らない田舎者であることを如実に表している。 >>41 実に田舎者の考え方で笑える 逆だよ、都会の人間は都会のことしか知らないし知る必要がない なぜか田舎の人間は都会のことも知ろうとするw > 逆だよ、都会の人間は都会のことしか知らないし知る必要がない だから世界が狭くて無知になりやすい > なぜか田舎の人間は都会のことも知ろうとするw だから世界が広い C言語が出来た時の時代を考えれば十分 「変数名に日本語が使えない言語は糞」 って時代もそのうち来るよ >>44 残念ながらそうはなってないんだなw 狭く深くっていう世界だから 要するに田舎でな何をするにもオーバーヘッドが大きいってことな 今はネットでだいぶマシになったけどネット以前の情報収集考えたらアホでもわかる話 アホなデータ食わせるアホなやつのために堅牢な仕組みにする必要はない >>46 メモリが640kバイトしか使えなかった頃からのものだしな 大昔って端末やエディタなんかでも1行256とか1024バイト程度しか扱えなかったばず 昔は1行の長さを先に決めてファイルをクリエイトしました 途中で変更はできません 関数そのものじゃないが breakにラベル指定出来なかったのは設計ミスやろ gotoはラベルのスコープが広いから使いにくい。ループごとに別のラベル名を 付けないといけないし、ラベル名を別のループ用のものと書き間違えると 意図しない所へ飛んで行ってしまう。スパゲッティでバグの元。 ループにラベルを付ければ、スコープがそのループ内に限定され、そのループの 外にある別のループに同じラベル名を付けることができるから、書きやすく 読みやすい。例えば、こんな感じ。 for @outer (i = 1; i <= 3; i++) { for (j = 1; j <= 3; j++) { printf("%d, %d\n", i, j); if (i * j > 3) break @outer; } } for @outer (i = 1; i <= 5; i++) { for (j = 1; j <= 5; j++) { printf("%d, %d\n", i, j); if (i * j > 5) break @outer; } } 1000行のコードでbreak 7;とかされても、 どこに抜けるかわからんよな! ネストの数がわからないような巨大な構造は それだけで最低だ そんなんだと名前付きループにした所で @outerなんて名前が使い回されて 同じ名前のループがネストされて それこそ難読コードになる それならユニークなラベルによるgotoの方が良い >>57 くらいのループなら break 2; は名前を考える手間が無くて楽だし 見にくくもない とは書いたけど どっちも有るならどっちも欲しい どっちかだけげならbreak 2;の方が欲しい って感じ >>61 > そんなんだと名前付きループにした所で > @outerなんて名前が使い回されて > 同じ名前のループがネストされて > それこそ難読コードになる 無能の妄想w ループの先頭、ループの終わり、break部分 3箇所見ないとダメってだけでダメな仕様 >>64 なぜか自分の前提は > >>57 くらいのループなら なのにラベルにした途端にループの頭とbreakとループの終わりが一瞥でわからないとかアホすぎ 名前を付ける手間を許容するならgotoという解決法が既にある >>60 ネスト変わるような変更あるたびにbreakの引数勝手に書き換えてくれるエディタとかマクロが流行る >>67 ifとgotoあるからforもwhileもdoも要らんという主張か 本物のプログラマーだなw 歪んだ教育のせいで gotoに拒絶反応を示す人が多いんだよな 2重ループを抜けるなら素直にgotoを使えって アセンブラの jmp 1f とかを C でやりたいという話なのか? やってみりゃいいじゃん。プリプロセッサの出力を処理すればいい。 1 パスで出来ると思うよ。 ひょっとしてもう誰かがやってるかも。 for (i = 1; i <= 3; i++) { for (j = 1; j <= 3; j++) { printf("%d, %d\n", i, j); if (i * j > 3) goto outer; } } outer:; for (i = 1; i <= 3; i++) { for (j = 1; j <= 3; j++) { printf("%d, %d\n", i, j); if (i * j > 3) goto outer; } } printf("complete\n"); outer:; わざわざ言語拡張しなくても >>57 以上の事が実現出来る ラベルのスコープを狭くしたいという話のようだから マクロの中で使ってこそ真価を発揮するんじゃないかな。 フル仕様のパースが必要というわけではなく、かなり手抜きできそうではある。 あれば便利というのは否定しないが、C でそこまで必要かというと… { goto hoge; hoge:; } { goto hoge; hoge:; } これで二重になってたら困るしある意味なってなくても困るな マクロで二重以上のループってのもなかなか考えづらいなあ 一応、ラベル名をパラメータとする手もある 使う側のコストを考えるとgotoの為にパラメータを増やさないよな gotoを使わない主義者がよくやってるように 余分な変数を使って実装するんだろうね アセンブラだとマクロローカルラベルってのがあったりする ラベルを頻繁に使うので あと @@/@b/@fのように、 直近のラベルを指定する仕組みもある >>72 >>73 みたいなのって gotoの使いどころだと思うんだけだ gotoを使わない人はどう書いてるの? 特に >>57 の答えを聞いてみたい void print_data(void) { for (i = 1; i <= 3; i++) { for (j = 1; j <= 3; j++) { printf("%d, %d\n", i, j); if (i * j > 3) return; } } } print_data(); printf("complete\n"); void print_data(void) { for (i = 1; i <= 3; i++) { for (j = 1; j <= 3; j++) { printf("%d, %d\n", i, j); if (i * j > 3) return; } } } print_data(); outer より後に処理が続く場合 printf("complete\n"); "短い処理"をいちいち関数にしなくて済むから、break 2とかはあってもいいが、 長い処理は関数にしてないとろくにテストできないんだからgotoなんていらない gotoの基本的な使い方くらい知っておいた方が良いかと ループを抜ける為だけに関数を分けないといけなくなるし 挙げ句の果てに言語の欠陥とか言い出す 今のC言語ではネストしたループから抜けるのはフラグを使うかgotoしかないからたいていgoto使ってるけどgotoなんて野蛮なものはできたら使いたくないから他の言語で実装されてるラベル付きbreakなりレベル付きbreakが欲しいって話だろ 今更gotoの基本的な使い方ガーとか言ってる奴はどんだけ低レベルなんだよw あれ? returnで抜ける為に関数に分けるんじゃなかったの? gotoは野蛮とかいう歪んだ教育のせいで わざわざ変数を定義したりわざわざ関数を分けたりして わざわざ見にくいコードにしちゃう 生でポインタを扱う野蛮なC言語なんか使わないで 上品な言語を使った方が良いよ gotoじゃなくてgodowntoなら誰も文句言わなかった 自分は小規模な字句解析みたいなのでもgoto使うことがある。 ラベルで状態を表してgotoで遷移する。 goto使わなかったら状態を変数に入れて、 ループの中でswitchで場合分けするようなコードになって辛い。 ループの中のswitchでループを抜けるのに gotoを使うんじゃ? 次の状態を返す関数ポインタでループすればいんじゃないの? >>87 returnで抜けるためというか、 1. gotoで抜けたい 2. 関数にするか 3. あ、そもそもコードが複雑なんだな 4. 関数にして正解だった こんな感じかな。 gotoで抜けたいと思う=コードが複雑になってるという警鐘だと思ってる。 で>>82 みたいな意味不明な関数の分け方をすると >>57 は、より複雑な記述をしたいっていう主張だし gotoに親を殺された人の言うことは支離滅裂 理由が後付けだからそうなる > で>>82 みたいな意味不明な関数の分け方をすると なんで意味不明? そもそもその処理に意味をもたせてから言おうよw 処理に意味をもたせると、関数にしたほうが良いと思うからさ > 理由が後付けだからそうなる 質問の方が先なのに、理由を先に言えるわけがないw Q. 多重ループから抜けるのに、gotoは必要ですか? A. 必要ありません。多重ループが必要になるぐらい複雑なら関数にしますから これが普通だから、後付にはならないよね。 じゃあ>>57 はどういうつもりで書いたんでしょうかね? 話を戻して ・ループを抜けた後に関数の後処理が必要な場合 ・ループを抜けた後にローカル変数を使った処理をする場合 ・他、意味的に関数内で処理したい場合 はどうするの? > ・ループを抜けた後に関数の後処理が必要な場合 前処理を関数の中でするな > ・ループを抜けた後に関数の後処理が必要な場合 戻り値を返せ >・他、意味的に関数内で処理したい場合 自分で具体例が思いつかないなら出すな コピペミスったな >・ループを抜けた後にローカル変数を使った処理をする場合 戻り値を返せ >>106 なにが? ってか、もう少し具体例を書けよ。 それみれば設計がおかしいという結論になる 例えて言うなら、パーサーの処理の中でネットワークにアクセスしたい時困るから ネットワークモジュールはグローバルにアクセスできるようにしておくべき みたいなことを言ってるようなもんだよ。それは設計がおかしい。 int func(int n){ ロック ループ アンロック return 結果; } int func(int n){ ループ 値を加工 return 値 } >>108 「ループ」という言い方がおかしい。 ループで「実装」しているのであって やっているのはなにかの「処理」だろう? int func(int n){ ロック 処理 アンロック return 結果; } 「処理」という名前をつけたくなるならば、 そこは独立した関数にするべきだろう double sigma(const double *a){ ループで総和と2乗和と数を計算 標準偏差を計算 return 標準偏差 } int func(int n){ int a[10] = {0}; ループ aから値を計算 return 値 } 関数分けってのは意味、機能、汎用性、...で分けるべきであって 単にループを抜けるのにreturnを使いたいから分けるとかを考えるべきじゃない 素直にgotoの使い方を覚えた方が良いよ 意地はってないで >>118 だから意味とか汎用性とかで分けると 自然にループに抜けるときにreturnを使えば良くなるんだよ gotoでもreturnでも読めれば良い 但し1関数50行以上は読めないんで宜しく >>112 だから「ループ」と書くなっちゅうねんw 関数を設計するならこんな感じやろ? int func(int n){ int a[10] = {0}; memset_random(a, sizeof(a)); // a配列をランダムな値で埋める int chksum = chksum(a, sizeof(a)); // a配列のチェックサムを計算 return 値 } 関数の中でループしてようが何して用が関係ないわ sizeof(a) とか書くレベルの相手してたのか アホらしい >>119 じゃあ普通のbreakもいらないね まさか使ってないよね まあgotoあればbreakは要らんわなw そんな言語は使いたくないけど gotoもbreakも無い ループを抜けるときはreturn switchを抜ける時もreturm 関数は単一の処理しか出来ない こんな言語はイヤだね たとえ相手がアホであっても、しつこく絡むのもまたアホだと思うんだが… 自分より下の人間を叩くしか能がないんだろ ID:arH1mwfYなんてスルーでいいと思うんだがそれしか叩けないからいつまでたっても終わらないw >>132 自分で似たようなものを作ればいいだろ。汎用的なものがあっても使い勝手や性能で何かしら不満が出るのだから、自分の要求に合致するものを自分で作りな。 特定の用途においてローカルラベルが役に立つことも無くはないかもしれないな。 自分でそれをやるかどうかは別にして。 いずれにせよ、gcc では式の中で変数を宣言できるのだから ローカルラベルが可能になっても驚かないよ。 C言語の開発者によるgoto文の使い方を対象とした実証研究の結果、「goto文は無害だと考えられる」 https://developers.srad.jp/story/15/02/14/2017207/ longjmp についても調査してほしいな。 特に例は挙げないが、誰もが使っているようなプログラムでも結構使われてる。 longjmpは「設計上のミス」ではないんでは。 むしろそういう動作をする目的で設計・導入されたように思えるけど (longjmpに関するRationaleを読んでないので当てずっぽうw) 例外は setjump、longjumpて実装されてるんじゃないのかな? 違うのかな? >>143 普通じゃない 当時はPascalの文字数+文字列が普通 returnが1変数しか対応していないこと。 ポインター祭りになって可読性がウンコになる >>148 可読性がうんこなのはお前の能力が足りないから いろんな言語たらい回しにされるって不幸だよね。 こういうノーガキ垂れる奴がウチの職場にいなくて良かった〜ヽ(´▽`)/ >>147 OSのAPIは文字数じゃなくて 文字列byte列+デリミタ'$' みたいなのが多かったぞ >>151 それはCP/Mの文字列出力がそうなっていただけ 入力はC言語のfgets()なんかみたいにデリミタの '$' を付加したりしないよ MASM もそうだけど、$ は実際にメモリに配置されるのですか? それとも、db(アセンブラ命令)で長さを省略するためのものですか? すみません、>>153 です 送信した瞬間に自分の発言の矛盾に気がつきました… >>146 longjumbと例外に関して すばらしい文書があるからお読みなさって。 http://www.nurs.or.jp/ ~sug/a/super/longjmp.htm#sec36 そっちは Not Found ですよ http://www.nurs.or.jp/ ~sug/soft/super/longjmp.htm >>156 ありがとうございます、昔に読んだのに URL を失ってしまって…ずっと探していたんです >>155 ありがとうございます >>146 です 拝見いたします ありがとうございます。いや、longjmp をdisるような意図は無かったんだけど。 「シグナルとコールバック」も勉強になります。 http://www.nurs.or.jp/%7Esug/soft/super/signal.htm この辺りは man を読んでも使い方が解りにくいので… 関数じゃないけどこれやろ If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type. うんこ プログラマを信じろと言うけどさ じゃあ暗黙の型変換とか余計な節介やめてくれねーかな >>162 暗黙の型変換はワーニング出るようにできなかったっけ? >>138 まとめがおかしい 啓蒙活動の結果gotoの有害な使い方は極めて少なくなった というべきだろう ken thompsonがcreat()の最後のeを省いたのは失敗だったと 直すとしたらそこを直したいと >>170 K&Rの頃との互換性の為じゃないかな。 Cは、兎に角モノグサの為の様な仕様が多いよね。 一度馴染むと、BASICですら面倒くさい。 ある意味というか、Pythonは一応強い型付けでしょ。 >>1 fgets知らんのかな getsなんて使わない どうしても使う時はfgets(buf,size,stdin)とすればいいだけ >>176 Cはアセンブラで言うところのアドレッシングが充実 visual studioでscanf()使ったらエラーになった visual studioでscanf()使ったらエラーになった アセンブラの補助言語に何期待してスレ立ててんだかw 知ってる関数を並べるスレ それにしても知らな過ぎるけどw C言語はUNIXを作るために作ったんだから、それを流用したせいで、アプリケーションの作成には合わないところがあるのは当然。 https://ja.wikipedia.org/?curid=1022 「UNIXを開発するためにC言語が作り出された」と言われることがあるが、「The Development of the C Language」によると、これは正しくなく、経緯は以下の通りである。 C言語は、当初はあくまでもOS上で動くユーティリティを作成する目的で作り出されたものであり、OSのカーネルを記述するために使われるようになるのは後の展開である。 read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる