C言語なら俺に聞け 147
■ このスレッドは過去ログ倉庫に格納されています
Cの場合には文法がスカスカだから、 ポインタで → 何でも出来る、とならないと上達しにくい。(演繹) この場合は → shared_ptr、では無理だ。暴走出来ない。(暗記) だから「暗記」ベースな奴は文法リッチな言語を選んだ方がいい。 (ただしポインタがあまりに汎用性がありすぎて最適化等に問題があり、 結果、他言語では色々制限を付けられてきたのはご存じの通り) 逆に「たったこれだけの文法で全て表現出来るなんてステキ」と思える奴は CやJavaScript等の文法スカスカ言語の方が向いてる。 JavaScriptがゴミゴミ言われながらもここまで残っているのもこの点が大きい。 あれは使える奴が使ったら凄く使える言語だ。 ただ、今のJavaScriptプログラマの大半がゴミなのも事実だが。 Cの授業が全く無駄だ、という話も出所はここだ。 プログラミングなんて、結局、「代入、条件分岐、関数呼び出し、ループ」でしかなく、 ループですら代入と条件分岐で実装出来るのだから冗長だ。 一応チューリング完全であるbrainfuckは関数呼び出しすらないので、これも冗長とも言える。 そしてCの授業で行われるのはまさに「代入、条件分岐、関数呼び出し、ループ」だけであり、 これでどうやって初音ミクが歌って踊るのだ?と初心者には思えるだろう。 最終的にはGPUを介してVRAM上に代入(ラスタライズ)しているだけだとしても、 それが初心者に見えるはずもない。 (もっとも、今の3Dベースの2D《テクスチャとして貼ってるだけ》だと ラスタライズ結果をVRAMに戻しているかも怪しいが) ただ、MITがSICPを止めたのと同様、今時初心者がCをやる必要はない。 DrawLineで線が描ける、HTML出力したら絵が出る、で済む連中がCやるのが間違ってる。 逆に、デバイスドライバ等を書いたり、 計算機自体の専門家(HighPerformanceComputing)等を目指すならCは必修になる。 メモリーリークについて質問です プログラム終了時に残ってしまったものに関してはOSが解放してくれるから対処しなくていいと聞きました 今までデバッグしてメモリーリークが出ると無くなるまで結構あれこれやってたんですが全部無駄だったんでしょうか >>753 終了時には解放してもらえるけど、メモリリークしたままだと動き続けられないじゃん。 たまに再起動してもらうの? あーいや想定してるのはちょっとした処理を行って出力して落ちるだけのプログラムなんです ループの中で何回もmallocしてメモリを食いつぶすとかそんなことも無くて、ただ終了時まで動的確保した変数が解放されてないみたいな そういう状況でお願いします >>755 そういう限定的な条件では解放は省略するって方針もあるかもね。 終了パターンがいろいろあると解放するだけでも一苦労だったりするし。 ただせっかく作ったそのコードは制約が多く他には転用しづらかったりと資産としての価値は低いと思う。 そもそもデバッグでメモリリークを発見とか言ってるとなると、メモリの管理はしっかりしてて解放を省略していることも設計に入ってる、という状況ではないんじゃないの? それはメモリを管理できてないってことじゃないのかな。 そんな場当たり的なことやってると大きなコード書けないよ。 メモリリークを潰させるのは、メモリを解放すること自体が目的というよりメモリを管理させる教育的な目的じゃないかね。 いや教育というか、上司が作ったAPIを利用して機能作れって指示が出ててですね そのAPIが上で説明したように変数解放しないままプログラム終了してたって状況です んでこれいいんですかこうすれば治りますがみたいなこと言ったらいいんだ勝手に解放されるかと ともあれそういう方針が有りだということは分かりました。どうもです そのAPIを流用するのは難しいな。 しないつもりなのかも知れないが。 まあしかしできればメモリリークしない方が良いな。 そのままだと常駐するプログラムのループの中で使えないし。 >>757 上司の指示ならそのままにしとけばいい メモリーリークしてもプロセス終了で解放されるから問題なし って言う奴は一定数いて説得しても改心しないから放置しとくしかない 後々何かで事故った時のためにドキュメントに書いとけ たいていドキュメントは失われるので俺ならソースコメントに書いておくな。 「2018/09/06 メモリ解放してないので注意(先輩の指示で改修見送り)」 そりゃ、そういう状況では解放処理は抽象的な書き方にすべきなんですよ。 freeがなければ安心できないのって病気に近いよ。 どういう状況か知らんけど > こうすれば治りますがみたいなこと 言ってるにも関わらず対応しないのは宗教に近いよ >>755 mayersだったかdinkumの人だったか忘れたけど、これはリソースリークじゃないって力説してて、 自分も同じセリフを言ってみたくてmain関数で確保したものを開放せずにいたら、 あとからそのmainだった関数に再入しないといけない要件が増えて涙した。 (小物ツールだったのに…) というわけでfreeしようぜ >>757 > ちょっとした処理を行って出力して落ちるだけのプログラム > 上司が作ったAPIを利用して機能作れって指示 × API ○ ツール 上司が作ったちょっとした「ツール」を使って(データの一部を切り出してきて)パイプ等で受ける場合、 そのツールがプロセス終了時に解放してないと文句を言うのは煙たがられる。 それは「意識高い系」すぎるし、そもそも君の担当範囲に何も悪影響はない。 そんなことはいいからお前の担当部分のバグを直せ、と思われているはず。 一応言っておくとfreeもタダではないので速度は落ちる。 必ずその後にプロセスが終了すると分かり切っているのなら放置もありだし、そっちの方が速い。 大方、精々1000行以下の上から下までつるっと動くだけのプログラムで、 最初に1回ワーク領域としてmallocして終わり、のパターンだろ。 割とどうでもいいね。実行形式のみでの配布なら問題になることはない。 (俺ならfreeしておくが。理由は>>766 と同じで、流用するときにバグるから) なお「API」では通常、別プロセスを起動して呼び出すことはない。(俺の知る限り) 本来「ツール」と表現すべき所を意図的に「API」と言うなら、相当な悪意だと受け取られる。 ただ単に間違ったのなら、お前は上司に対していちいち文句を言わず、 指示されたようにやるべきレベルだ。わきまえた方がいい。 ソースコードにコメント、は止めた方がいい。そこは上司への不満を書く場所ではない。 直すなら「潜在バグ」として正式登録、その必要がないと判断するなら放置したほうがいい。 数年後、君によって後輩が助かれば君は讃えられるだろうし、 そうでなければ君は痛かった奴だなと思われる、ただそれだけの話だ。 コメントだけ残して修正してませんでした、ってのはマジで痛いだけだから止めとけ。 誰も助からないし、生産性がない。 (バグを踏んだ後輩から見れば責任逃れせずにちゃんと直しておいてくれ、としか見えない) そもそもそのツールがバグってたのなら作った上司の責任だし、 上司がそれを面倒がるのなら、そのソースの管理責任を君が受け取って自由に出来るはず。 そんなに速度のことが気になるなら、グローバルでドカッと変数確保すりゃ良いだろう >>755 きちんと malloc() した領域を free() できているように、それを重点的に書き直していくだけでも、プログラムの構造がわかりやすくなり、バグも少なくなるとおもいます >>768 そうそう、malloc() したポインタを線形リストに登録しておいて、最後にまとめて free() するとか… >>768 さすがにそれはセンスがないのでは ドカッと一発mallocならまだしも ツールに使う程度の小規模なプログラムなら、 グローバルで取ろうと気にしなくて良いと思うけどな >>768 さすがにプロセス起動/終了の方がfreeより100倍以上重いはずなので、 ここでfreeを速度の為にケチる、というのはナンセンス。 ただ、free一個分速いのは事実だし、Cは精神論的に速度を希求するからねえ。 多分、最初はグローバルで固定長バッファだったが、 もっと大きなサイズも必要になって、面倒だったからど頭でmallocに変更、だと思うよ。 割とありがちなパターンだし、この場合はfreeしない文化のような気もする。 最近はあまりないけど実メモリーがカツカツの状態だとfree()する為にディスクからページを読み込む処理が大量に発生してなかなかアプリケーションが終了しないと言う事があったりする exitって重いの? まあfreeするもんだと決め打ちはしたらあかんよ freeしてないコードを池沼が書いて freeしてないコードを 実績があるコードといって池沼が確かめもせずそのままコピペして流用する よくあること つまり池沼の代重ねで どんどんメモリリークが酷くなっていく dtr は作るけど、コメントに「プロセス終了時にしか実行しないのでfreeしてない」と書いて放置してるわ >>774 ああ、なるほど。 そういえばスワップがある時にFireFoxを落とすだけでもずいぶんかかっていたのを思い出した。 なるほどそこでスラッシングしてたのか。 >>779 うちの FireFox も終了時にモタモタしてるから、そうなるのが分かってる時はタスクマネージャーで殺したりするw つかアプリは終了時に保存するもの保存したらリソースそのままで exit しちゃう方がいい気がしてきたわ。 freeでスワップからページ読み込みするってマジ? freeだけならdirtyページドロップするだけだと思ってたわ freeがいちいちSVCなんかするわけねえだろ それと、おまえスワップとページを混同してるな >>781 ポインタ書き換えたりするから一度ディスクからメモリに戻さざるを得ないのでは? ものすごく大きい領域を一括で確保した場合は全部戻す必要ないけど細切れに沢山確保してあるのをバラバラにfreeしたらなりそうだよね。 >>781 free()すると管理領域を書き換えるためにページインが必要になる ランタイムの実装とOSにどう伝えてるかの間のことを考え出すと激しく禿る思考停止 unix/linux な人はどう実装してるか確認してるの? >>782 そうなの? 例えばWindowsだとfreeは内部でHeapFreeをコールしてるのかと思ってた。 HeapFreeって恐らくSVC伴うよね? >>787 DDR3 16G です、もっとほしい… >>781 単純に free だけの話じゃなく、自分が作り上げたオブジェクトツリーを辿りながら free していく過程でその(結局解放する)オブジェクトをページインすることになる。 C でオブジェクトとか言うことの是非は置いといて。 >>787 Windows7 で 3GB。 Linux な家サーバだと 1GB。 Cプログラミングスタイルも細かくブロック分けてスタック節約するようなセコセコ型が基本。 個人で使うための大したことないツールだったか、 この件の実験用に作ったプログラムだったか忘れたけど…。 そこそこ沢山のデータを、ひとつ読み取ってはmallocで確保した領域に保存、 ハッシュテーブル(値が重複する要素はリンクド・リストでつなぐ)にブチ込んで 個々のデータはプログラム終了まで破棄しない、て条件。 終了前に真面目にfreeして回るのと、そのままexitしてOSに片付けてもらうのと、 比較してみたらfreeのループ処理が意外に重かったんで、 解放処理の関数を残したまま呼び出し部だけ注釈にして、 // 解放すべきだと思いつつも無駄に重いんでOSに上手いことやってもらう みたいな自分用のメモを残したわ。我ながらどっちつかずの折衷案。 >787 Win7以降で最低4G、可能なら8G。3Dゲームやるなら16G以上。 XP時代は2Gか3Gだった。 >>787 今使ってるマイコンのRAMは64バイト メモリを確保しっぱなしでわざわざ明示的に解放コードを書かないことはある C++じゃなくてCだと特に 組み込みだとそもそも終了処理なんて物が無かったりする >>792 (俺はそういう状況に遭遇したことがないが、)やるなら、 freeを生かしたまま残し、その直前でexit、 exitに「// free が遅いからここで強制終了」とコメントかな。 そもそもCはやたらfreeするようには出来てない。それはK&Rのfree実装をみても明らかだ。 C++や他GC言語のようにインスタンスを個別にmalloc/freeした方が プログラミング的に美しく、自由度があるのも確かだが、 古来C流なら > 個々のデータはプログラム終了まで破棄しない、て条件。 が分かっている時点で纏めてmallocし、内部的に切り出して使う、とかじゃないかな? 大きなテキストを1発mallocで確保し、内部的に改行コードで区切って使うみたいに。 初期データはインミュータブル扱い、追加/変更はインスタンス毎個別に確保、だ。 ただこれだと結局コードは増えてしまうし、個別freeすべきかのフラグを導入するか、 解放関数でインミュータブル領域かどうかを判定する必要がある。 そういうのが面倒だと最初から全部C++流にインスタンス毎個別に確保になり、 その分動作が遅くなるが、コード自体は綺麗に(統一的に)保たれる。 結局、コードを取るか、手間かけてその分高速化するか、でしかない。 気にならない程度なら、俺はC++流の個別確保の方がコードが綺麗だからいいと思うが。 (つまり今の君の実装) 気になるのなら、選択の余地無く高速化するしかないし。 >>795 むしろ C++ の方が気安く new するから、そっちの方が放置したくならないかね。 根っこのオブジェクトを delete すれば後のはデストラクタがやってくれるとかで面倒さは少ないのかもしれないが。 何にしても、許されるのはきちんと解放できるけどあえてしない、ってのだけだな。 なんだかよく分かんないし面倒からOSに尻拭いしてもらうなんてのはダメだ。 fork で起こした子プロセスがメモリを free せず終了しても問題無いが、それをスレッドにしましょうなんてなった瞬間に破綻する。 商業プログラムだとラッパだらけで直接free呼ばんし。 freeなしという選択肢は常に確保しとけばよい。 >>786 え、WindowsにSystem z版てあるんだっけ? >>799 え?System z限定の話だったの? >>801 スーパーバイザコールを拡大解釈して、いわゆる特権モードを伴うシステムコールとして書いてたわ。 誤解があったらすまん。 >>781 mmap経由ならOSによってはそうかもな >>802 おk じゃあ、その前提で話を戻そう freeはISO/IEC9899では宣言と引数の意味のみが規定され実装は未規定だ 782でああ言ったのは、freeする度毎にタイムスライスを放棄するような実装は まずなかろうということだ >>804 まず、786で書いたようにあくまで「思ってた」だけで確固たる根拠はないことを前提に。 freeするならどこからか借りていたメモリ領域を返却するわけで、仮想メモリ返却にはMMUを使ったページ管理が必要だよね? 仮想メモリページ管理はメモリマネージャー的なカーネルモードドライバが必要なはずで、つまり解放時にはシステムコールを伴う。 ただ、HeapFree時に直接カーネルモードで解放が実行されずメモリマネージャがガーベジコレクション的に後々回収するなら、あなたの言うとおりfree時にユーザーモードで閉じて処理されるかも。 このへん、Linuxとかどういう実装になってるんだろうね? 画期的なメモリ確保方式とか出来ないかな 例えばさ、名前付きタグを付けてメモリ確保し、 名前指定で一気に解放できるようにするとか >>805 freeがメモリを返却する相手が何者なのかは未規定だぞ いちいちOSへ直に返しているとおまえさんの言うとおりだが スタティックリンクライブラリがOSから大口で借りたメモリを切り売りする スタイルならシステムコールの回数をガクンと減らせる よくある実装は1MiBあたりを境に小容量は切り売りで大容量は直にという形 >>808 いや、俺はANSI Cとかの規定の話してるんじゃなくて、SVCって単語からこの議論がスタートしてるのでモダンなOS上の一般的な実装の話をしてると思ってたんだけど、違ったのか。 確かにアプリ起動時にある程度のヒープを最初から用意ってのはありそう。 >>806 ソフトで実現で良いなら、簡単に実現できそうね。 てかsmbか何かでそういう実装見たことあるような? >>805 Linux+glibcの環境なら、mallocは昔ながらのbrkシステムコールの方法と mmapシステムコールの方法が状況に応じて使われる freeしたときmmapをmunmapしてOSに返されることもある はず。…たしか >>811 なるほど、勉強になります。 やっぱりOSのメモリ管理をちゃんと理解しようとしたら参考になるので最低限glibcとmmapを読まないといけないね。 ちらっとmmapとglibc斜め読みしてみた。 こんな世界があるんだとソフトエンジニア7年目にして新しい視点が開眼しそう。 色々気付きをくれた方々、ありがとうございました。 >>806 ゆとりりゅうのすごいめもりかくほ、まで読んだ。 マジレスすると、 > 名前付きタグ このコストが分からない馬鹿はCを学ぶ意味はあるだろう。 スクリプト言語しか使ったことのない奴に多いが。(例:ハッシュはタダだと思ってる) >>805 > 仮想メモリ返却にはMMUを使ったページ管理が必要だよね? お前は中途半端に勉強してるな。まあ悪いことではないが。 ページの単位は今も昔も4KBだ。その方法ではインスタンス毎の確保は出来ないと分かるだろ。 >>812-813 読むのは勝手だが、あまり関係ないところに深入りしても意味はないぞ。 7年目なら業務関連は一通り出来るようになっており、知識を横に広げているのかもしれないが、 OS関連の知識があってもな。 時間が有り余っていて手当たり次第に知識を吸収するのも一つの手だが、 もし大きい(10,000行以上)のを書いたことがないのなら、 まずは規模の限界(複雑さの限界)に挑戦する方がいいと思うが。 >>814 >もし大きい(10,000行以上)のを書いたことがないのなら、まずは規模の限界(複雑さの限界)に挑戦する方がいいと思うが。 そうですね… 1万行ですか… せいぜい 1000 行程度までしかやったことがありません、モチベーションが続かない・燃料切れ、という感じです 行数が多ければいいというものでもないと思うが・・・ だいぶ初歩の質問なんだけどextern宣言って本当に必須なの?コンパイラというかリンカによるのかもしれないけど、つけなくても同じ動作するよね? 今まで疑問に思わず書いてたけど、これを聞かれて色々試してみると実際つけなくても同様の動きしてるように見えるし、ちゃんと答えられなかったわ >>816 ならお前なりの妥当な規模を測る単位でも示せよ >>816 否定ばかりして新しい提案をしない典型的無能要員 >>817 ライブラリ関数をコールするだけなら extern は要らない子です、でもライブラリが独自の変数を定義して公開しているのならば extern がないと困ります 例えば <stdio.h> の stdin, stdout, stderr >>817 > 1. Declaration can be done any number of times but definition only once. > 2. “extern” keyword is used to extend the visibility of variables/functions(). > 3. Since functions are visible through out the program by default. The use of extern is not needed in function declaration/definition. Its use is redundant. > 4. When extern is used with a variable, it’s only declared not defined. > 5. As an exception, when an extern variable is declared with initialization, it is taken as definition of the variable as well. > https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/ 下のコード例が見やすい。 これが規格と合致しているのかは知らん。 >>821 しかし C には仮定義 "tentative definition" があったりして混迷するのです ISO/IEC 9899:1999 6.9.2.2 the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0. 私には、これはリンカの仕業であってコンパイラが自ら行動しているようには見えないのですが… glibc は malloc だけで 5000行あるってね。 上級者スレに解説動画があったけど面白かったよ。 >>814 >ページの単位は今も昔も4KBだ。その方法ではインスタンス毎の確保は出来ないと分かるだろ。 ごめん、これがよく分かんない。 MMUのページ単位が4KBなのと、インスタンス毎の確保はできないってのがつながらない。 てかここで言うインスタンスって何? >>824 インスタンス1つにいちいち4KBもアロケートするのかって話だろ >>825 別に1回のmallocで必ずしも毎回4KBのベージを割り当てる必要ないのでは? mallocするのが小さいサイズなら確保済みの4KBの空いてるとこから割り当てれば良いし。 実際にはどういう実装になってるか知らんけど。 そもそも動的メモリ確保/解放と仮想メモリ管理は直接関係ない話 組み込みだとMMUなんて存在しない環境もある >>826 それだとお前のレス > freeするならどこからか借りていたメモリ領域を返却するわけで、仮想メモリ返却にはMMUを使ったページ管理が必要だよね? > 仮想メモリページ管理はメモリマネージャー的なカーネルモードドライバが必要なはずで、つまり解放時にはシステムコールを伴う。 と矛盾するだろ。 お前は日本語が駄目なタイプか? >>828 そういう意味では、厳密には「4KB以上のfree」と書くべきだったかな? ページサイズに言及したのは先の書き込みの後なので別に論理矛盾はないと思うけど。 >>826 うん、俺もそう思うし 実際の実装もそうなっているのが多い ただし4KBではなく1MiBとかだけど >>829 ぷろぐらみんぐのまえににほんごをがんばれ 業務に関係なく完全に知的好奇心からのmalloc実装の想像だったので、やっぱりglibc読んでみよう。 色々レスくれた人、ありがとう。 ファイルシステムの管理領域が大きくなりすぎて、 4KB以下のページサイズには出来ない 4MBで千個、4GBで百万個のページを管理しないといけないから、 管理領域だけでも、100MB以上になる だから、ページサイズをもっと大きい、2MBにすると、 2GBで千個、2TBで百万個のページを管理できるから、今のHDD の容量に対応できる HDDだとシリンダ容量との親和性を考えないとね だけどSSDが普及してる今どきの事情だとどうなんだろう >>833 > 4MBで千個、4GBで百万個のページを管理しないといけないから、 > 管理領域だけでも、100MB以上になる 管理領域ってどう計算してるの? >>836 すまん、聞き方がアホだった その1領域が100Byteになる理由を聞きたかった utf8procというUnicodeライブラリを使いたいのですが、C99に準拠してるかどうかって分かりますか? 「emulate C99 bool」というコメントがソースコードにあったのでおそらくC89あたりからサポートしていると思うんですが。 https://github.com/JuliaStrings/utf8proc >>839 C99に準拠している そのコメントの少し前に 「MSVC prior to 2013 lacked stdbool.h and inttypes.h」ってコメントがあるからWindowsの古い環境のためにboolとかを定義しているだけだね OSのすべての機能を学びたいなら、ムック本の Linuxエンジニア養成読本、第3版、2016 カーネル、起動処理、仮想記憶、 ファイルシステム、シェルスクリプトなど ファイルシステム・管理領域の仕組みなどを読んで タネンバウム先生の本でしょ すごい弟子を育てた伝説の師匠 なにそれ、すごい面白そう! アラサーだけどまだまだ青二才だしとっても勉強になります! >>840 ありがとうございます! これでUnicodeが古い環境で心置きなく使えますわ。 ここのスレの人はValgrindは 使っているんだろうか。 メモリリークとか考えれば ぜひ使うべきツールだと思う。 https://qiita.com/tjun/items/e9d2f7da3c94eb0240d8 便利だよね ただ役に立ってるときはクソコードを触ってるときでもあると思う 変数中の "1" のビット数を数える効率的方法ありますか? aが32ビットとして for (i = 0; i < 32; i++) { j = j + a & 1; a = a >> 1; } みたいに1ビットずつカウントするしかないでしょうか あるいは、8bitとかで区切ってテーブルを引いて加算とかでしょうか(16ビットや32ビットのテーブルは現実的でないので) a=(a&0a55555555)+(a>>1 &0a55555555); a=(a&0a33333333)+(a>>2 &0a33333333); a=(a&0a0F0F0F0F)+(a>>4 &0a0F0F0F0F); a=(a&0a00FF00FF)+(a>>8 &0a00FF00FF); a=(a&0a0000FFFF)+(a>>16 &0a0000FFFF); a = (a & 0x55555555) + (a >> 1 & 0x55555555); a = (a & 0x33333333) + (a >> 2 & 0x33333333); a = (a & 0x0F0F0F0F) + (a >> 4 & 0x0F0F0F0F); a = (a & 0x00FF00FF) + (a >> 8 & 0x00FF00FF); a = (a & 0x0000FFFF) + (a >> 16 & 0x0000FFFF); ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる