190

メモリがデータ、ヒープ、スタック、コードの4つのセグメントに分割されていることを考慮すると、グローバル変数、静的変数、定数データタイプ、ローカル変数(関数で定義および宣言)、変数(メイン関数で)、ポインターが実行されます。 、および動的に割り当てられたスペース(mallocおよびcallocを使用)はメモリに格納されますか?

私はそれらが次のように割り当てられると思います:

  • グローバル変数------->データ
  • 静的変数------->データ
  • 定数データ型----->コード
  • ローカル変数(関数で宣言および定義されている)-------->スタック
  • main関数で宣言および定義された変数----->ヒープ
  • ポインタ(たとえばchar *arr、、int *arr)------->ヒープ
  • 動的に割り当てられたスペース(mallocおよびcallocを使用)-------->スタック

これらの変数は、Cの観点からのみ参照しています。

私はCに慣れていないので、間違っている場合は訂正してください。

4

9 に答える 9

259

あなたはこれらのいくつかを正しく理解しました、しかし質問を書いた人は誰でも少なくとも1つの質問であなたをだましました:

  • グローバル変数------->データ(正しい)
  • 静的変数------->データ(正しい)
  • 定数データ型----->コードおよび/またはデータ。定数自体がデータセグメントに格納され、それへの参照がコードに埋め込まれる状況については、文字列リテラルを検討してください。
  • ローカル変数(関数で宣言および定義されている)-------->スタック(正しい)
  • 関数で宣言および定義された変数main----->ヒープもスタックします(教師はあなたをだまそうとしていました)
  • ポインタ(例:char *arrint *arr)------->コンテキストに応じて、ヒープデータまたはスタック。Cを使用すると、グローバルまたはstaticポインターを宣言できます。この場合、ポインター自体がデータセグメントに含まれます。
  • 動的に割り当てられたスペース(、、を使用malloccalloc-------- realloc>スタックヒープ

「スタック」は正式には「自動ストレージクラス」と呼ばれていることは特筆に値します。

于 2013-01-29T17:39:05.243 に答える
161

それらのメモリセグメントについて知りたいと思うかもしれないそれらの将来の訪問者のために、私はCで5つのメモリセグメントについての重要なポイントを書いています:

いくつかの注意:

  1. Cプログラムが実行されるたびに、プログラム実行のためにRAMにメモリが割り当てられます。このメモリは、頻繁に実行されるコード(バイナリデータ)、プログラム変数などを格納するために使用されます。以下のメモリセグメントは、同じことについて説明しています。
  2. 通常、変数には次の3つのタイプがあります。
    • ローカル変数(Cでは自動変数とも呼ばれます)
    • グローバル変数
    • 静的変数
    • グローバル静的変数またはローカル静的変数を持つことができますが、上記の3つは親タイプです。

Cの5つのメモリセグメント:

1.コードセグメント

  • コードセグメントは、テキストセグメントとも呼ばれ、頻繁に実行されるコードを含むメモリ領域です。
  • バッファオーバーフローなどのプログラミングバグによってオーバーライドされるリスクを回避するために、コードセグメントは読み取り専用であることがよくあります。
  • コードセグメントには、ローカル変数( Cでは自動変数とも呼ばれます)やグローバル変数などのプログラム変数は含まれていません。
  • Cの実装に基づいて、コードセグメントには読み取り専用の文字列リテラルを含めることもできます。たとえば、printf("Hello, world")そうすると、文字列「Hello、world」がコード/テキストセグメントに作成されます。sizeこれは、LinuxOSのコマンドを使用して確認できます。
  • 参考文献

データセグメント

データセグメントは以下の2つの部分に分割され、通常はヒープ領域の下、または一部の実装ではスタックの上にありますが、データセグメントがヒープ領域とスタック領域の間にあることはありません。

2.初期化されていないデータセグメント

  • このセグメントは、 bssとも呼ばれます。
  • これは、以下を含むメモリの部分です。
    1. 初期化されていないグローバル変数 (ポインター変数を含む)
    2. 初期化されていない定数グローバル変数
    3. 初期化されていないローカル静的変数
  • 初期化されていないグローバルまたは静的ローカル変数は、初期化されていないデータセグメントに格納されます
  • 例:グローバル変数int globalVar;または静的ローカル変数static int localStatic;は、初期化されていないデータセグメントに格納されます。
  • グローバル変数を宣言して初期化すると、0またはNULLそれでも初期化されていないデータセグメントまたはbssに移動します。
  • 参考文献

3.初期化されたデータセグメント

  • このセグメントは以下を保存します:
    1. 初期化されたグローバル変数 (ポインター変数を含む)
    2. 初期化された定数グローバル変数
    3. 初期化されたローカル静的変数
  • 例:グローバル変数int globalVar = 1;または静的ローカル変数static int localStatic = 1;は、初期化されたデータセグメントに格納されます。
  • このセグメントは、初期化された読み取り専用領域と初期化された読み取り/書き込み領域にさらに分類できます。初期化された定数グローバル変数は初期化された読み取り専用領域に配置され、実行時に値を変更できる変数は初期化された読み取り/書き込み領域に配置されます
  • このセグメントのサイズは、プログラムのソースコードの値のサイズによって決定され、実行時に変更されません
  • 参考文献

4.スタックセグメント

  • スタックセグメントは、関数内で作成された変数(関数はメイン関数またはユーザー定義関数である可能性があります) を格納するために使用されます。
    1. 関数のローカル変数(ポインター変数を含む)
    2. 関数に渡される引数
    3. 差出人住所
  • スタックに格納されている変数は、関数の実行が終了するとすぐに削除されます。
  • 参考文献

5.ヒープセグメント

  • このセグメントは、動的メモリ割り当てをサポートするためのものです。プログラマーがメモリを動的に割り当てたい場合、Cでは、、、、またはメソッドを使用して割り当てmallocられcallocますrealloc
  • たとえば、その場合int* prt = malloc(sizeof(int) * 2)、8バイトがヒープに割り当てられ、その場所のメモリアドレスが返され、ptr変数に格納されます。ptr変数は、宣言/使用方法に応じて、スタックまたはデータセグメントのいずれかになります。
  • 参考文献
于 2016-01-24T20:46:17.467 に答える
13

間違った文章を修正しました

constant data types ----->  code //wrong

ローカル定数変数----->スタック

初期化されたグローバル定数変数----->データセグメント

初期化されていないグローバル定数変数----->bss

variables declared and defined in main function  ----->  heap //wrong

main関数で宣言および定義された変数----->スタック

pointers(ex:char *arr,int *arr) ------->  heap //wrong

dynamically allocated space(using malloc,calloc) --------> stack //wrong

pointers(ex:char * arr、int * arr)------->そのポインター変数のサイズはスタックになります。

nバイトのメモリを(mallocまたはを使用してcalloc)動的に割り当て、それを指すようにポインタ変数を作成していると考えてください。これでn、メモリのバイトがヒープにあり、ポインタ変数は4バイト(64ビットマシンの場合は8バイト)を必要とします。これnは、メモリチャンクのバイトの開始ポインタを格納するためにスタックになります。

注:ポインター変数は、任意のセグメントのメモリーを指すことができます。

int x = 10;
void func()
{
int a = 0;
int *p = &a: //Now its pointing the memory of stack
int *p2 = &x; //Now its pointing the memory of data segment
chat *name = "ashok" //Now its pointing the constant string literal 
                     //which is actually present in text segment.
char *name2 = malloc(10); //Now its pointing memory in heap
...
}

動的に割り当てられたスペース(malloc、callocを使用)-------->ヒープ

于 2013-01-29T17:40:06.547 に答える
9

一般的なデスクトップアーキテクチャは、プロセスの仮想メモリをいくつかのセグメントに分割します。

  • テキストセグメント:実行可能コードが含まれています。命令ポインタはこの範囲の値を取ります。

  • データセグメント:グローバル変数(つまり、静的リンケージを持つオブジェクト)が含まれます。読み取り専用データ(文字列定数など)と初期化されていないデータ(「BSS」)に細分されます。

  • スタックセグメント:プログラムのダイナミックメモリ、つまりフリーストア(「ヒープ」)とすべてのスレッドのローカルスタックフレームが含まれます。従来、CスタックとCヒープは、両端からスタックセグメントに成長していましたが、安全性が低すぎるため、実践は放棄されたと思います。

ACプログラムは通常、静的ストレージ期間のオブジェクトをデータセグメントに配置し、動的に割り当てられたオブジェクトをフリーストアに配置し、自動オブジェクトをそれが存在するスレッドのコールスタックに配置します。

古いx86リアルモードや組み込みデバイスなどの他のプラットフォームでは、状況が根本的に異なる場合があります。

于 2013-01-29T17:42:31.743 に答える
7

これらの変数は、Cの観点からのみ参照しています。

C言語の観点から、重要なのは範囲、範囲、リンク、およびアクセスです。アイテムが異なるメモリセグメントにどのようにマッピングされるかは、個々の実装によって異なり、それは異なります。言語標準では、メモリセグメントについてはまったく説明されていませ。最新のアーキテクチャのほとんどは、ほとんど同じように機能します。ブロックスコープ変数と関数引数はスタックから割り当てられ、ファイルスコープ変数と静的変数はデータまたはコードセグメントから割り当てられ、動的メモリはヒープから割り当てられ、一部の定数データは読み取り専用セグメントに格納されます、など。

于 2013-01-29T17:58:06.807 に答える
4

ストレージについて覚えておく必要があることの1つは、as-ifルールです。コンパイラは、変数を特定の場所に配置する必要はありません。代わりに、コンパイルされたプログラムが抽象Cマシンのルールに従って抽象Cマシンで実行されたかのように動作する限り、好きな場所に変数を配置できます。これは、すべての保存期間に適用されます。例えば:

  • すべてにアクセスされていない変数は完全に削除できます-ストレージがありません...どこにもありません。-生成されたアセンブリコードにどのように含まれているかを確認します42が、の符号はありません404
  • アドレスが取得されていない自動保存期間の変数は、メモリに保存する必要はまったくありません。例として、ループ変数があります。
  • constメモリ内にある、またはconstメモリ内にある必要のない変数。foo-コンパイラーは、それが効果的であることを証明し、constその使用をコードにインライン化できます。bar外部リンケージがあり、コンパイラーはそれが現在のモジュールの外部で変更されないことを証明できないため、インライン化されません。
  • で割り当てられたオブジェクトはmalloc、ヒープから割り当てられたメモリに存在する必要はありません。-コードにへの呼び出しがなくmalloc、値42もメモリに保存されておらず、レジスタに保持されていることに注意してください。
  • したがって、によって割り当てられたオブジェクトと参照は、メモリをリークする必要のないmallocオブジェクトの割り当てを解除せずに失われます。free
  • によって割り当てられたオブジェクトは、Unixenのプログラムブレーク( )のmallocのヒープ内にある必要はありません。sbrk(0)
于 2019-07-06T06:21:41.100 に答える
1

ポインタ(例:char * arr、int * arr)------->ヒープ

いいえ、スタックまたはデータセグメントに存在する可能性があります。彼らはどこを指すことができます。

于 2013-01-29T17:35:09.180 に答える
1
  • 変数/自動変数--->スタックセクション
  • 動的に割り当てられた変数--->ヒープセクション
  • 初期化されたグローバル変数->データセクション
  • 初期化されていないグローバル変数->データセクション(bss)
  • 静的変数->データセクション
  • 文字列定数->テキストセクション/コードセクション
  • 機能->テキストセクション/コードセクション
  • テキストコード->テキストセクション/コードセクション
  • レジスタ->CPUレジスタ
  • コマンドライン入力->環境/コマンドラインセクション
  • 環境変数->環境/コマンドラインセクション
于 2014-12-10T07:05:45.610 に答える
0

分解分析を使用したLinuxの最小限の実行可能な例

これは標準で指定されていない実装の詳細であるため、特定の実装でコンパイラが何を行っているかを見てみましょう。

この回答では、分析を行う特定の回答にリンクするか、ここで直接分析を提供し、すべての結果をここに要約します。

それらはすべてさまざまなUbuntu/GCCバージョンにあり、結果はバージョン間でかなり安定している可能性がありますが、バリエーションが見つかった場合は、より正確なバージョンを指定しましょう。

関数内のローカル変数

それmainまたは他の機能:

void f(void) {
    int my_local_var;
}

に示すように:<valueoptimized out>はgdbで何を意味しますか?

  • -O0:スタック
  • -O3:こぼれない場合は登録し、そうでない場合はスタックします

スタックが存在する理由の動機については、「x86アセンブリのレジスタで使用されるプッシュ/ポップ命令の機能は何ですか?」を参照してください。

グローバル変数とstatic関数変数

/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;

/* DATA */
int my_global_implicit_explicit_1 = 1;

void f(void) {
    /* BSS */
    static int my_static_local_var_implicit;
    static int my_static_local_var_explicit_0 = 0;

    /* DATA */
    static int my_static_local_var_explicit_1 = 1;
}
  • 初期化されている0か、初期化されていない(したがって、暗黙的に0):.bssセクションに初期化されている場合は、次も参照してください。.bssセグメントが必要なのはなぜですか。
  • それ以外の場合:.dataセクション

char *char c[]

に示すように:静的変数はCおよびC ++のどこに格納されていますか?

void f(void) {
    /* RODATA / TEXT */
    char *a = "abc";

    /* Stack. */
    char b[] = "abc";
    char c[] = {'a', 'b', 'c', '\0'};
}

TODOは、非常に大きな文字列リテラルもスタックに配置されますか?または.data?または、コンパイルは失敗しますか?

関数の引数

void f(int i, int j);

関連する呼び出し規約を通過する必要があります。例:https ://en.wikipedia.org/wiki/X86_calling_conventions for X86は、各変数の特定のレジスタまたはスタックの場所を指定します。

次に、で示されているように、<valueoptimized out>はgdbで何を意味しますか?-O0次にすべてをスタックに丸呑みし、-O3可能な限りレジスタを使用しようとします。

ただし、関数がインライン化されると、通常のローカルと同じように扱われます。

const

型キャストできるので違いはないと思います。

逆に、コンパイラが一部のデータが書き込まれないと判断できる場合は、理論的には、.rodataconstでなくてもデータを配置できます。

TODO分析。

ポインタ

それらは変数(数値であるアドレスを含む)なので、他のすべてと同じです:-)

malloc

は関数であるためmalloc、この質問はあまり意味がありません。malloc

int *i = malloc(sizeof(int));

*iはアドレスを含む変数であるため、上記の場合に該当します。

mallocが内部でどのように機能するかについては、Linuxカーネルが特定のアドレスを内部データ構造に書き込み可能としてマークし、それらが最初にプログラムによってアクセスされると、障害が発生し、カーネルがページテーブルを有効にして、アクセスを許可します。 segfaulなしで発生:x86ページングは​​どのように機能しますか?

ただし、これは基本的にexec、実行可能ファイルを実行しようとしたときにsyscallが内部で行うこととまったく同じであることに注意してください。ロード先のページにマークを付け、そこにプログラムを書き込みます。以下も参照してください。 Linux?ロード先にいくつかの追加の制限があることを除いてexec(たとえば、コードは再配置可能ではありません)。

に使用される正確なシステムコールmallocmmap、最新の2020実装であり、過去brkに使用されていました。malloc()はbrk()またはmmap()を使用しますか?

ダイナミックライブラリ

基本的mmapにメモリにアクセスします:https ://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

環境変数とmain'sargv

初期スタックの上:https : //unix.stackexchange.com/questions/75939/where-is-the-environment-string-actual-stored TODOなぜ.dataにないのですか?

于 2020-03-18T14:25:52.363 に答える