C言語の変数は一体どこに保存されているのか

C言語の変数はすべてテキスト領域(code segment)、データ領域(静的領域、data segment)、そしてお馴染みのスタック領域とヒープ領域のどれかに保存されます。

領域に分ける理由

このような複数の領域に分割されたのは、アドレスレジスタがアクセスを許されるアドレス以上にアクセスをするという動機があります。メモリアドレスをずらして分割をすることで、16bitのアドレスレジスタは本来アクセスできる64kb以上の1mbのメモリ空間にアクセスができるようになります。ちなみに、このような仕組みが初めて実装されたのはIntel 8086 CPUからだそうです。

出典: brain.cc.kogakuin.ac.jp

テキスト領域

コード領域とも呼ばれます。この領域には機械語に翻訳されたCのプログラムが保存されます。テキスト領域のメモリは一番低番地に保存されます。テキスト領域の大きさはコンパイルが終わった後に決まり、固定されます。

なぜ最低番地?

ヒープとスタックのオーバーフローがテキスト領域を侵すのを防ぐため一番低番地になっています。

データ領域

データ領域にはグローバル変数と静的変数が保存されます。データ領域はさらに、初期化されてない変数(例:char c;)を保管するbssと初期化されてる変数(例:int i = 1;)を保存するdata領域に分けることができます。bssのほうがメモリの高番地に位置してます。データ領域の大きさもコンパイル後に固定されます。

出典: tcrosley

スタック/ヒープ領域

スタック領域はLIFO(last in first out)ですべてのローカル変数が保存されます。

ヒープには動的メモリ確保で確保されたメモリが高番地に向かって保存されます。スタックとヒープが重なるとOSにより、スタックオーバーフロー、もしくはmalloc()などの失敗が起こります。

TL;DR

メモリの低番地から順に:

  • テキスト領域 (機械語に翻訳されたC)
  • データ領域
    • data (初期化された変数)
    • BSS (初期化されてない変数)
  • ヒープ (動的メモリ)
  • スタック (ローカル変数)

標準、規格

このようなルールみたいな仕切りでCのメモリ管理は成り立っているのに、意外なことにC言語のメモリ領域は規格で定まってなく、実は業界が勝手作り上げた標準(らしきもの)なのです。なので、OSやコンパイラにより領域の使い方が違う場合があります。

参考