C++ では、ストレージ クラス指定子 static がデータ領域からメモリを割り当てます。「データ領域」とはどういう意味ですか?
8 に答える
私は「データ領域」という用語になじみがありませんが、メモリは「コードセクション」と「データセクション」に分けられることがよくあります。コードは前者に、データは後者に存在します。これがここでの意味だと思います。
古典的には、両者の間に区別はありません。ただし、最新のオペレーティング システムの多くは、データ セグメント内でのコードの実行を禁止できます (CPU がこの区別をサポートしている場合)。これは、「実行なし」のように「NX フラグ」のキャッチ フレーズを使用する場合があり、悪意のあるコード インジェクションの一部のケースを効果的に防ぐことができます。
/EDIT: C++ 標準では「データ領域」について言及されていないことに注意してください。
領域の名前は、プラットフォーム、コンパイラ、およびリンカーによって異なります。
一般に、次のようなものがあります。
- プログラム テキスト: 実行可能なコード空間。
- 定数: 非実行定数。
- スタック: スタック。
- bss: C/C++ 用語で広く言えば「静的」です。「シンボルで始まるブロック」
- data: 初期化されていないグローバル
- heap: 実行時に割り当てられるストレージ。
この場合、問題のドキュメントでは、伝統的に bss セグメントと呼ばれるものに「データ領域」という名前を使用しています。
C 用語では、ストレージ クラス指定子の「静的」は、プログラムの存続期間中存在し、ゼロまたは初期化子の値に初期化されるメモリを意味します。例では:
static int s_value_one;
static int s_value_two = 123;
main() の最初のステートメントの時点で、s_value_one の値はゼロであることが保証され、s_value_type の値は 123 です。これがどのように実現するかは、実装上の問題です。
Konrad が言ったことに加えて、変数を static として宣言することは、基本的に、ヒープやスタックではなく、プログラムがロードされるときにそのメモリが割り当てられることを意味します。歴史的に、重要なアプリケーションで静的変数のみを使用することは、アプリケーションのメモリ フットプリントが実行時に変化しないことを意味し、そのため、リソースの制限により失敗する可能性が低くなりました。これが最新のオペレーティング システムに当てはまるかどうかはわかりません。
コンパイラに出力の一部として mapfile を生成させる場合、データを含むすべてのさまざまなセクションの内容を確認できます。
コンラッドが言ったこと。
コードセクションに配置されている場合、データを読み取ることができない CPU がまだ存在すること、およびその逆があることを付け加えたいと思います。これらは数十年前より一般的でしたが、組み込みの世界ではまだ生きています。
簡単に言えば、リンカーは同じ種類のシンボルをグループ化するだけです。PC には、多くの場合、単純なコードおよびデータ領域以上のものがあります。初期化されていないデータ、読み取り専用データ、およびその他の OS 依存のものの領域もあります。
実行可能ファイルには多くの情報が含まれています。
実行可能ファイルには、物理ファイル内に多くのタイプ/クラスのデータが格納されています。
例:
- 実行可能コード命令
- 資力
- 依存関係情報(このバイナリが依存するdll)
- このバイナリからエクスポートされるシンボル
等
整理する方法が必要です
OSがすべての情報を簡単に見つけて実行可能ファイルをロードし、動作させることができるように、.exeファイル形式内のこのすべての情報。この目的のために、PE(ポータブル実行可能ファイル)と呼ばれる一般的なバイナリ形式(もちろんM $によって作成されます)がWindowsの世界で使用されます。私が今リストしたすべての情報(およびそれ以上)は、バイナリのさまざまなセクションで詳細に説明されています。
.dataセクション
そのようなセクションの1つが.dataセクションです。.dataセクションには、初期化されたすべてのグローバルデータと静的データが含まれ、.bssセクションには、初期化されていないグローバルデータが含まれます。
グローバル用に別のセクションが必要なのはなぜですか?
グローバルは、プログラムの存続期間中に存在するメモリ領域に作成され、上書き/再利用される可能性のあるスタックのような一時的なデータ構造ではないため、グローバルのように動作します。(通常の自動変数のように)。
コンパイラ
したがって、これらの変数はヒープ内の永続的なアドレスに割り当てる必要がありますが、残念ながら、コンパイル時には知ることができません。したがって、コンパイラはすべてのグローバル変数と静的変数をこの.data / .bssセクションに配置し、これらの変数を参照する命令は、.data/.bss内のこれらの比較的永続的なアドレスを参照します。
リンカ
リンカは、実行可能ファイルを実世界でロードするときに、これらのセクションを配置する必要がある場所を決定し、グローバルを参照する命令がプログラムメモリ内の現在の実仮想アドレスを参照するように、これらの一時アドレスのFIXUPを作成します。
これで、.dataセクション/エリアとは何か、グローバルにそのエリアにスペースを割り当てる必要がある理由と、それがプログラムにリアルタイムでどのように役立つかがわかりました。PE形式とリンカーおよび.dataセクションなどをグーグルで検索すると、リンクが取得されます。
少しグーグルで、これらの主題に関する詳細情報をここで見つけました:
データが行き着く場所はたくさんあります。通常、ローカル変数はスタックに割り当てられ、malloc (または「new」のデフォルト バージョン) を使用してヒープに割り当てることができます。ただし、静的データは通常、プログラムの開始時に割り当てられ、どこにでも配置される可能性があります。正確には、コンパイラ、OS、および実行形式によって異なります。
「データ領域」はヒープを指していると思いますが、ローカル変数は通常スタック上にあります。
または、この変数に割り当てられたメモリが実行可能ファイルの .data セクションにあることを意味しますが、これは Windows と PE 形式に固有のものです。