定数変数はどこに格納されているのだろうか。グローバル変数と同じメモリ領域ですか?それともスタックにありますか?
14 に答える
それらがどのように格納されるかは、実装の詳細です (コンパイラによって異なります)。
たとえば、GCC コンパイラでは、ほとんどのマシンで、読み取り専用の変数、定数、およびジャンプ テーブルがテキスト セクションに配置されます。
特定のプロセッサが従うデータ セグメンテーションに応じて、5 つのセグメントがあります。
- コード セグメント - コード、ROM のみを格納
BSS (またはシンボルで開始されたブロック)データセグメント - 初期化されたグローバル変数と静的変数を格納します。- スタック セグメント - 関数のリターン アドレスなどに関するすべてのローカル変数とその他の情報を格納します。
- ヒープ セグメント - すべての動的割り当てはここで行われます
データBSS (またはシンボルで開始されたブロック)セグメント - 初期化されていないグローバル変数と静的変数を格納します
データ セグメントと BSS セグメントの違いは、前者は初期化されたグローバル変数と静的変数を格納し、後者は初期化されていないものを格納することに注意してください。
さて、定数変数がどこに格納されているかを伝えなければならないのに、なぜデータセグメンテーションについて話しているのですか...それには理由があります...
すべてのセグメントには、すべての定数が格納される書き込み保護領域があります。
例えば:
- ローカル変数である const int がある場合、それはスタック セグメントの書き込み保護領域に格納されます。
- const var で初期化されたグローバルがある場合、それはデータ セグメントに格納されます。
- 初期化されていない const var がある場合、BSS セグメントに格納されます...
要約すると、「const」は単なるデータ QUALIFIER です。つまり、最初にコンパイラが変数を格納する必要があるセグメントを決定する必要があり、次に変数が const である場合は、書き込み保護された領域に格納される資格があることを意味します。その特定のセグメント。
次のコードを検討してください。
const int i = 0;
static const int k = 99;
int function(void)
{
const int j = 37;
totherfunc(&j);
totherfunc(&i);
//totherfunc(&k);
return(j+3);
}
通常、i
テキスト セグメントに格納できます (固定値を持つ読み取り専用の変数です)。テキスト セグメントにない場合は、グローバル変数の横に格納されます。ゼロに初期化されている場合、「bss」セクション (ゼロ化された変数が通常割り当てられる場所) または「data」セクション (初期化された変数が通常割り当てられる場所) にある可能性があります。
が未使用であるとコンパイラがk
判断した場合 (これは、単一のファイルに対してローカルであるため可能性があります)、オブジェクト コードにまったく表示されない可能性があります。totherfunc()
その参照への呼び出しk
がコメント化されていない場合はk
、どこかにアドレスを割り当てる必要があります - それは と同じセグメントにある可能性がありますi
。
定数 (定数の場合、それでも変数ですか?)j
は、おそらく従来の C 実装のスタックに表示されます。(comp.std.c ニュース グループで質問していた場合、自動変数がスタックに表示されるとは標準では規定されていないと誰かが言うでしょう。幸いなことに、SO は comp.std.c ではありません!)
参照によって変数を渡したため、変数を強制的に表示したことに注意してください。おそらく、定数整数へのポインターを期待する関数に渡しました。アドレスが取得されていない場合は、コードから完全に最適j
化k
できます。を削除するi
には、コンパイラはプログラム全体のすべてのソース コードを認識している必要があります。他の翻訳単位 (ソース ファイル) でアクセスできるため、簡単には削除できません。プログラムが共有ライブラリの動的ロードにふける場合、二重にそうではありません-それらのライブラリの1つがそのグローバル変数に依存している可能性があります。
(文体的に - 変数i
と にj
は、より長く、より意味のある名前を付ける必要があります。これは単なる例です!)
コンパイラ、システム機能、コンパイル中の構成によって異なります。
gcc
.text
特に指示がない限り、読み取り専用の定数をセクションに置きます。
オフコースではない、なぜなら
1)bssセグメントには、非初期化変数が格納されていましたが、明らかに別のタイプがあります。
(I) large static and global and non constants and non initilaized variables it stored .BSS section.
(II) second thing small static and global variables and non constants and non initilaized variables stored in .SBSS section this included in .BSS segment.
2)データセグメントは初期化された変数であり、3つのタイプがあります。
(I) large static and global and initlaized and non constants variables its stord in .DATA section.
(II) small static and global and non constant and initilaized variables its stord in .SDATA1 sectiion.
(III) small static and global and constant and initilaized OR non initilaized variables its stord in .SDATA2 sectiion.
私が上で述べたように、小さい手段と大きい手段はコンパイラに依存します。たとえば、小さい手段は8バイト未満であり、大きい手段は8バイトを超えて等しい値です。
しかし、私の疑問は、ローカル定数がどこにあるのかということです??????
通常、それらは読み取り専用のデータ セクションに格納されます (グローバル変数のセクションには書き込み権限があります)。そのため、アドレスを取得して定数を変更しようとすると、segfault とも呼ばれるアクセス違反が発生する可能性があります。
ただし、実際にはハードウェア、OS、およびコンパイラに依存します。
これはほとんど経験に基づいた推測ですが、定数は通常、コンパイルされたプログラムの実際の CPU 命令に即時データとして格納されていると言えます。つまり、ほとんどの命令には、データを取得するためのアドレス用のスペースが含まれていますが、定数の場合、スペースは値自体を保持できます。
一部の定数は保存されていません。
次のコードを検討してください。
int x = foo();
x *= 2;
x = x+x;
メモリから数値 2 をロードする必要性を減らすため、コンパイラが乗算を に変換する可能性があります。
アドオンとして、リンクプロセス中に最終的な実行可能ファイルのメモリレイアウトが決定されることを知っているように.COMMONと呼ばれるもう1つのセクションがあり、異なる入力ファイルからの共通シンボルが配置されます.この共通セクションは実際に落ちます. .bss セクションの下。
まったく保存されない場合があります。
次のようなコードを検討してください。
#import<math.h>//import PI
double toRadian(int degree){
return degree*PI*2/360.0;
}
これにより、プログラマーは何が起こっているのかを把握できますが、コンパイラーはコンパイル時に定数式を評価することで、その一部を最適化することができます。ほとんどのコンパイラーはそうしています。つまり、値 PI が結果のプログラムにない可能性があります。まったく。