0

グローバル データと静的データ以外に、データ セグメントには何が割り当てられていますか?

定数文字列もデータセグメントに割り当てられ、同じ文字列定数への参照が行われると同じメモリが使用されることをどこかで読んだことを覚えています

元:

char* returnPointer()
{
   char *p = "hello world"

   //some code

   return p;
}

void foo()
{
   char *s = "hello world"
  //some code
}

上記のコードでは、

  1. 定数「hello world」のメモリは、データ セグメントまたはスタック (他のローカル変数と同様) に割り当てられますか?

  2. データ セグメントに割り当てられている場合、p と s の両方が同じ場所を指していますか?

4

3 に答える 3

2

定数「hello world」のメモリは、データ セグメントまたはスタック (他のローカル変数と同様) に割り当てられますか?

いいえ、読み取り専用の実装で定義されたメモリ領域に割り当てられます。C 標準は、それを格納する場所を正確に定義していません。文字列リテラルが静的な保存期間を持つことを保証するだけであり、ユーザー プログラムによって変更されるべきではありません。

データ セグメントに割り当てられている場合、 と の両方が同じ場所pを指していますか?s

これは、使用されているコンパイラがどれほど効率的であるかにのみ依存します。効率的なコンパイラは、1 つの文字列のみを最適化して割り当てる場合がありますが、別のコンパイラはそうしない場合があります。

とにかく、これらの動作は言語のユーザーとは何の関係もないため、これらの動作に依存する必要があります。これらは、ユーザープログラムが依存すべきではない実装の詳細です。

于 2012-05-31T05:59:20.487 に答える
2

定数「hello world」のメモリは、データ セグメントまたはスタック (他のローカル変数と同様) に割り当てられますか?

これはコンパイラ固有ですが、通常、文字列リテラルは初期化されたデータ セグメント (多くの場合、初期化されたデータ セグメントの特別な読み取り専用部分) に存在します。文字列リテラルがもっともらしいスタック上に存在する可能性のあるアーキテクチャを知りません。

データ セグメントに割り当てられている場合、p と s の両方が同じ場所を指していますか?

それはコンパイラ次第です。

gcc 4.4.6 を使用してコードをコンパイルすると、次のように表示されます。

        .section        .rodata
.LC0:
        .string "hello world"
        .text
.globl returnPointer
        .type   returnPointer, @function
returnPointer:
.LFB0:
        .cfi_startproc
        ...
        movq    $.LC0, -8(%rbp)
        ...
        ret
        .cfi_endproc
.LFE0:
        .size   returnPointer, .-returnPointer
.globl foo
        .type   foo, @function
foo:
.LFB1:
        .cfi_startproc
        ...
        movq    $.LC0, -8(%rbp)
        ...
        ret
        .cfi_endproc
.LFE1:
        .size   foo, .-foo
        .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"

ここで、文字列リテラルは読み取り専用のデータ ( .rodata) セクションに格納されます。コンパイラは、まったく同じリテラルがコンパイル単位で 2 回使用されていることを認識できるほど賢く、そのコピーを 1 つだけ に配置し.rodataます。

于 2012-05-31T05:59:55.770 に答える
0

最初の質問に対する答えは、"hello world" は読み取り専用メモリ領域に保存されるということです。

2 番目の質問の答えは、そうかもしれないし、そうでないかもしれないということです。同じ住所である保証はありません。

以下の詳細情報:

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

初期化されたデータ セグメント。通常は単にデータ セグメントと呼ばれます。データ セグメントは、プログラムの仮想アドレス空間の一部であり、プログラマによって初期化されるグローバル変数と静的変数が含まれています。

変数の値は実行時に変更できるため、データセグメントは読み取り専用ではないことに注意してください。

このセグメントは、初期化された読み取り専用領域と初期化された読み取り/書き込み領域にさらに分類できます。

たとえば、C の char s[] = “hello world” で定義されたグローバル文字列と、メイン (つまりグローバル) の外にある int debug=1 のような C ステートメントは、初期化された読み取り/書き込み領域に格納されます。const char* string = “hello world” のようなグローバル C ステートメントは、文字列リテラル “hello world” を初期化された読み取り専用領域に格納し、文字ポインター変数 string を初期化された読み書き領域に格納します。

例: static int i = 10 はデータ セグメントに格納され、global int i = 10 もデータ セグメントに格納されます

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

「bss」セグメントと呼ばれることが多い初期化されていないデータ セグメントで、「シンボルで始まるブロック」を表す古代のアセンブラ オペレータにちなんで名付けられました。このセグメントのデータは、プログラムが実行を開始する前に、カーネルによって算術 0 に初期化されます。

初期化されていないデータは、データ セグメントの最後から始まり、ゼロに初期化されているか、ソース コードで明示的に初期化されていないすべてのグローバル変数と静的変数を含みます。

たとえば、変数は static int i; と宣言されています。BSS セグメントに含まれます。たとえば、int j; と宣言されたグローバル変数。BSS セグメントに含まれます。

于 2012-05-31T05:59:44.050 に答える