C言語でプログラムを作って動かした場合、プログラム領域、静的領域、スタック領域、ヒープ領域などと4つの領域が使われるそうですが、

これは何の仕様でそう決まっているのでしょうか。

C言語の仕様?OSの仕様?コンパイラの仕様?

(ちなみにK&Rを見てみましたが、そのようなことは記述されていませんでした)

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2014/07/20 15:50:03
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答3件)

id:sea-show No.1

回答回数15ベストアンサー獲得回数1

ポイント67pt

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

回答になっていないですが、C99にも書いてなさそう?ですね。stackやheapで検索してもひっかからないです。

id:watercooler No.2

回答回数289ベストアンサー獲得回数51

ポイント67pt

ノイマン型に由来するCPUを使っているからよ。
ノイマン型 - Wikipedia

アドレス付けされた記憶装置とそれらをつなぐバスを要素に構成され、命令(プログラム)とデータを区別せず記憶装置に記憶する。


「区別せず」は、コンピュータはどこに何が書かれているかなんて知らないから、どのアドレスをどのように使うかをプログラマが決めなければならないってことなのよ。

最初に必要なのはプログラムを書いておく領域よね。そのつぎに静的なデータを書く領域、ルーチン呼び出しで局所変数を退避したりする場所としてのスタック、最後にプログラマが自由に使えるヒープと大まかに4つに分けたの。

プログラムを書き始めるアドレスはCPUによって決まっているからプログラム領域はおのずと定まってくるわ。スタックもマシン語レベルで用意されているものよ。それらにたいして静的領域とヒープの境は実はあいまいなの。ふたつをまとめてデータ領域と呼ぶ場合もあったりするほどにね。
8bitCPUのハンドアセンブルを少しかじれば理解しやすくなるわ。今さら8bitが必要かはわからないけど64bitCPUでハンドアセンブルなんて考えたくないもの。必要だと思うならZ80で探せばいまもたくさんの情報があるわよ。

他1件のコメントを見る
id:watercooler

スクリプト言語ならスクリプトはヒープ領域に展開される

プログラム本体からみたらスクリプトファイルは手続きの書かれているデータにすぎないの。
データを展開するなら自由に使えるヒープ領域を使うのは当然の流れでなくて?

http://q.hatena.ne.jp/1404552223 でJULYさんに教わったこともうお忘れかしら?

スクリプトが書かれたファイルは、その処理系に対する入力データに過ぎません。

2014/07/13 23:34:00
id:DQNEO

それはわかるのですが、私の質問は「何の仕様でそれが決まっているのか?」です。

2014/07/18 06:57:55
id:snow0214 No.3

回答回数470ベストアンサー獲得回数116

ポイント66pt

最初にC言語が主に動いていたCPU「PDP-8」と、そこから派生した32ビット機械語命令セットのVAXが大きく影響しています。K&RはVAXがあることが当たり前の人たちなので、あえてテキストには出てきません。

遅れて勃興したIntelのCPUを参考にしていたら、プログラム領域とスタック領域で十分だったはずです。

結局、VAX系にヒープの概念があったことが、後の仮想記憶にスムーズに繋がりました。
今でこそWindowsは仮想記憶が利用できますが、Intelのアーキテクチャは、そもそもヒープや仮想記憶を想定していませんでした。Intelの32ビット命令は、VAXより10年以上後に登場したにもかかわらず、まったく美しくありませんでした。Pentiumが登場するまで、常に物理メモリでやりくりせざるを得ませんでした。

結局、メモリ管理はVAX方式が王道であることが、いまのWindowsやLinuxで証明されています。
ゆえに、そのメモリ管理をプリミティブに実現しているC言語は、いまでもプログラミング言語の基礎として学ばれているのです。

  • id:Vacuum
    プログラムのロードモジュールのしようとしては、ホストコンピュータ.UNIX.WINDOWS など総て、同様の仕組みで構成されています。

    この仕様は、ハードウェア上でソフトウェアを動かすという仕組みである限り、そういう決まりということですね。
  • id:practicalscheme
    今のシステムはほとんどそうですが、必ずしもそうしなければならないってものでもないです。また、ノイマン型であることは必要条件ですが十分条件ではありません。

    初期の、メモリが極めて少なかった頃のマシンでは、動的アロケーションが無かったり(つまりヒープ領域がない)、逆にスタック領域がない(戻りアドレスやセーブレジスタはリンクトリストで管理)というものもありました。

    また、現在ではプロセス実行時の領域区分はOSのバイナリ規約と考えるのが良いと思いますが、初期のパソコン用OSなどではOS側はメモリをひとまとめでプログラムに渡し、それをどう割り当てるかはプログラム側に任されていました。メモリがきつかった頃は特にコード領域と静的データ領域の区分が曖昧で、コードに混じったデータを実行中に直接書き換えることも良くありましたね。

    色々な歴史的経緯を経て、今のようなモデルに落ち着いて来たってことです。
  • id:TransFreeBSD
    セグメントの概念はかなり初期のC言語・コンパイラ/a.out/UNIXからあったようです。
    #Multicsからあったようですし、snow0214さんの書かれたようにPDP/VAXにもつながる概念だと思います。
    ですので、パソコンは影響を受けた方で与えた方ではないので、ここで出すのはちょっと違う気がします。
    #また、X86は仮想記憶はありませんがセグメントの概念はあります(しかもセグメントは4つ)。
    むしろメモリが少なく高価だったからこそ、それを効率よく使うためにページングやセグメントが出来たんだと思います。
    そして、コードがありデータがありスタックがあれば3つのセグメントが出来、OSやハードにメモリ管理の機能があればヒープもできるのは必然の気がします。
    あと、コードとデータを区別するのはむしろ非ノイマン型の方向性だと思います。

    最後に、そもそものこの質問については、このころはそもそも言語/OS/コンパイラの区別があいまいなので、どの仕様かもあいまいというか、仕様というより規約だと思います。
  • id:DQNEO
    結論としては、仕様ではなく規約であるということですかね?
  • id:TransFreeBSD
    規約とか言いながらあれですが、よく考えるとコード領域とデータ領域はオブジェクトファイルに作られ(コンパイラの領分)ますが、ヒープ領域はmallocの実装次第(ライブラリの領分≒これもC言語の範疇?)※ただしOSにも依存?、スタック領域はOSとハードに依存するのかなとも思います。
    そう考えると仕様とか規約とかいうカッチリとしたものと言うほどではないかもしれません。
    まあ、当時UNIXとCを創った三人がどう考えていたのかはわかりませんが。

    とか言いつつ経緯を調べてました。

    -C言語の元となったB言語の元となったBCPLのアセンブラはtext, data他のセグメントを持ち、VMはスタックポインタをもつ。
    -- https://archive.org/stream/intcode_documentation/INTCODE_documentation#page/n15/mode/2up
    -unix 6th(75年)ですでにtext, data, bssの3セグメントがある
    -- http://man.cat-v.org/unix-6th/5/a.out
    -ヒープ領域から確保するmallocの前身allocもある
    -- http://man.cat-v.org/unix-6th/3/alloc
    -最初にunixが創られたPDP-7にはスタックポインタが無いが、その後のPDP-11にはある

    メモリモデルは75年には概ね今の形にはなってたっぽいです。
    その後、x86系やDOS/Windowsでアレンジはあるものの踏襲されていると言っていいのかな?
    そうやって暗黙と言うほどでも無いですが仕様というか規約というか了解事項がデファクトになったといったところでしょうか。
  • id:DQNEO
    ふむふむ。
    つまりはただの慣習であるということですかね。

    ありがとうございます!

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません