なぜ本は「コンパイラがメモリ内の変数にスペースを割り当てる」と言っているのですか?


18

なぜ本は「コンパイラがメモリ内の変数にスペースを割り当てる」と言うのでしょうか。それを実行する実行可能ファイルではありませんか?たとえば、次のプログラムを書くと、

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

コンパイルし、実行可能ファイル(program.exeにします)を取得します。program.exeを実行すると、この実行可能ファイル自体が変数fooにスペースを割り当てるようにコマンドを実行します。しませんか?本が「コンパイラがこれを行う...そうする」と言い続ける理由を説明してください。


11
どの本について話しているの?
ウィルベル

4
「関連する質問」は別の質問にする必要があります。
シャヒーン


コンパイラーは、これを行うコード、または彼らが言っていることをコードを生成します。直接的または間接的に。
old_timer

FYI stackoverflow.com/questions/7372024/...コンパイラは、アライメントなどのためにメモリ内の知覚変数の場所を変更するように決定することができることをノート:stackoverflow.com/questions/17774276/...
NoChance

回答:


20

プログラムが実際に実行されたときにコンパイラ自体がなくなっているのは正しいことです。また、別のマシンで実行すると、コンパイラーは使用できなくなります。

これは、実際に独自のコードによって割り当てられたメモリを明確に区別するためだと思います。コンパイラは、メモリ割り当てを実行するコードをプログラムに挿入します(new、malloc、または同様のコマンドを使用するなど)。

したがって、書籍では、コンパイラがコードファイルで明示的に言及されていないコードを追加したとよく言われます。これが実際に起こっていることではないことは十分に真実です。この観点から、チュートリアルで言及されている多くのことは間違っていますが、かなり詳細な説明が必要です。


はい、それは私が信じていたことです。簡単な回答をありがとう!
平和的なコーダー

12
コンパイラーは、コンパイル中にスタックポインターへのオフセットで変数を代入することにより、スタック上の変数fooに割り当てます。mallocet によって行われるヒープ割り当てとはまったく関係ありません。al。
ウィルベル

@holger:もちろん、あなたの異議は技術的に正しいです。ただし、プログラムを使用する前に、スタックスペース自体を割り当てる必要があります(CPUアーキテクチャによっては、さまざまな方法で発生する場合があります)。私はこれがどのように起こるか詳細を見つけようとしましたが、あまり成功していません。
トールステンミュラー

2
メインスレッドのスタックサイズはリンカによって予約され、OSによって処理されると思います。カスタムスレッドの場合、ヒープ割り当てに似ています。つまり、呼び出し側は実行時にサイズを修正できます。
ウィルベル

4

変数に依存します。OSはヒープを割り当て、プログラムはスタックを割り当て、コンパイラはグローバル/静的なスペースを割り当てます。つまり、exe自体に組み込まれます。1MBのグローバルメモリを割り当てると、exeサイズは少なくとも1MB増加します


1
それはこの質問の目的ではありません。
フィリップ

2
実際には、ここにリストされている他の回答よりも質問に近いです。
ウィルベル

@ジェームスああ、これは私の経験ではありません。たとえば、int test[256][1024]; int main(){ test[0][0]=2; return 0; } この小さなプログラムには1MBが割り当てられていますが、1.4 KBのオブジェクトファイルと8.4 KBの実行可能ファイルのみが生成されます。ただし、正しい量のRAMを使用する必要があります。
ガレットクラボーン

1
グローバル用に保存された割り当てコマンドだけではいけませんか?intやcharなどのプリミティブを使用してすべての値をハードコーディングした場合、実行可能ファイルのサイズは、追加された変数の量よりも確実に大きくなります。などint a1=1,a2=2,...まで...し, a1048576=1048576;なければ、あなたは間違いなく私が思う1メガバイトより大きい何かを得るだろう。
ガレットクラボーン

2
exeのBSSセクションにデータを入力するものは何でも
ジェームズ

4

コンパイラ行うことは、コードを取得してマシンコードにコンパイルすることです。あなたが言及するのは、コンパイラーが翻訳するだけでよい良い例です。

たとえば、あなたが書くとき

int foo;

「私はコンパイラに[ 生成する出力で ]に、後で参照できるintに十分なRAMを確保するように要求するようにコンパイラに伝えているので、コンパイラはおそらくリソースIDまたは何らかのメカニズムを使用してfooを追跡します。マシンコードでは、アセンブリを記述する代わりにテキストファイルでfooを使用できます!ほら

コンパイラーがすべてのターゲットのプロセッサーとデバイスに手紙(または、おそらく小説/百科事典)を書いているので、これを見るかもしれません。文字はバイナリ信号で書かれており、(通常)ターゲットを変更することで異なるプロセッサに変換できます。「文字」やコンボは、あらゆる種類のリクエストやデータを送信できます。たとえば、プログラマが使用したこの変数にスペースを割り当ててください。


3

「コンパイラがメモリを割り当てる」と言うことは、文字通りの意味では事実上正確ではないかもしれませんが、それは正しい方法で暗示的なメタファーです。

実際に起こることは、コンパイラが独自のメモリを割り当てるプログラムを作成することです。ただし、メモリを割り当てるのはプログラムではなく、OSです。

したがって、実際に起こるのは、コンパイラがメモリ要件を記述するプログラムを作成し、OSがその記述を取得してそれを使用してメモリを割り当てることです。OSはプログラムであり、プログラムは実際には何もしないことを除いて、CPUによって実行される計算を記述します。CPUが実際には単なる複雑な電子回路であり、擬人化された小さな同胞ではないことを除きます。

しかし、プログラム、コンパイラ、およびCPUをコンピューターの内部に住んでいる小さな人々と考えるのは理にかなっています。実際にそうであるからではなく、それは人間の脳によく適合する隠metaだからです。

いくつかのメタファーは、あるレベルの抽象化で物事を説明するのに適していますが、別のレベルではうまくいきません。コンパイラのレベルで考える場合、コンパイルされるプログラムが実際に「メモリの割り当て」として実行されるときにメモリが割り当てられるコードを生成する行為を説明するのは理にかなっています。コンパイラがどのように機能するかを考えているとき、私たちは正しい考えを持っているのに十分近く、私たちがやっていたことを忘れるほど長くはありません。実行中のコンパイルされたプログラムのレベルでそのメタファーを使用しようとすると、奇妙な方法で誤解を招きます。


0

変数を格納する場所を決定するのはコンパイラーです。スタックまたは空きレジスターにすることができます。コンパイラがストレージを決定した場合、その変数にアクセスするための対応するマシンコードが生成され、実行時に変更することはできません。この意味で、コンパイラーは変数用のスペースの割り当てを担当し、最終的なprogram.exeは実行時にゾンビのように盲目的に動作します。

これを、malloc、new、または独自のメモリ管理などの異なる動的メモリ管理と混同しないでください。コンパイラは変数の保存とアクセスを処理していますが、別のフレームワーク/ライブラリで実際の値が何を意味するかは気にしません。例えば:

byte* pointer = (byte*)malloc(...);

実行時に、mallocは任意の数値を返す場合がありますが、コンパイラは気にしません。気にするのは、その数値を格納する場所だけです。


0

より正確なフレージングは​​次のとおりです。

C風の環境では、変数用に3種類のスペースがあります。

  • 静的変数の固定ブロック
  • 通常「スタック」と呼ばれる「自動」変数の大きなブロック。関数はエントリ時にチャンクを取得し、リターン時に解放します。
  • 「ヒープ」と呼ばれる大きなブロック。プログラム管理メモリの割り当て元です(malloc()または同様のメモリ管理APIを使用)。

最新のOSでは、ヒープメモリは実際には予約されず、必要に応じて割り当てられます。


0

はい、あなたは正しいです、この場合(関数で変数を宣言する)、あなたの本の文はおそらく間違っています:関数で変数を宣言すると、関数に入るときにスタックに割り当てられます。とにかく、コンパイラは状況を最適化する必要があります。関数が非再帰的である場合(それmain()が適切な候補である場合)、コンパイル時に(BSS上で) "割り当て"ても構いません。

(変数の存在場所に興味がある場合は、ダーティな方法でチェックできます(とにかく、objファイル構造を調べたくない場合はどうでしょうか?)。静的、動的、malloc()-allocatedなど。アドレスを表示します(読みやすくするために%Xフォーマッターを使用しますprintf()。スタックに存在する変数は、非常に異なるメモリアドレスを持ちます。)


0

実行時に行われるのは、スタックポインターを一定量だけバンプすることだけです。そのため、コンパイラは事前に決定します。

  • 関数に必要なスタックスペースの量。
  • スタックポインターからのオフセットで、すべての個々の変数が配置されます。

これは「割り当て」と呼ばれますが、もちろん、コンパイル時に実行中のプログラムのコンパイラーが持つモデルにのみ配置されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.