constストレージはどのように機能しますか?(項目2、スコットマイヤーズの効果的なC ++)


8

16ページのItem2(#definesよりもconsts、enums、およびinlineを優先する)で、Scottは次のように述べています。

また、優れたコンパイラは整数型のconstオブジェクトのストレージを確保しませんが...

分かりません。たとえば、constオブジェクトを定義すると、

const int myval = 5;

その後、コンパイラは値5を格納するために(intサイズの)メモリを確保しなければなりません

またはconstデータは特別な方法で格納されていますか?

これは私が思うコンピュータストレージの問題です。基本的に、コンピューターはconstオブジェクトをどのように格納して、ストレージが確保されないようにしますか?


3
明確なタイトルを提供する必要があります。元storage of const objectの質問のソースにはほとんど価値がありません。
Simon Bergot、2012

回答:


7

また、優れたコンパイラは整数型のconstオブジェクトのストレージを確保しませんが...

やや正しいステートメントは、コンパイラが整数型のconstオブジェクト用にデータメモリを確保しないというものです。つまり、プログラムメモリと交換します。フォンノイマンアーキテクチャでは2つのアーキテクチャに違いはありませんが、ハーバードなどの他のアーキテクチャでは、区別がかなり重要です。

何が起こっているのかを完全に理解するには、アセンブリ言語が処理のためにデータをロードする方法を思い出す必要があります。データをロードするには、2つの基本的な方法があります。特定の場所からメモリを読み取る(いわゆるダイレクトアドレッシングモード)、または命令自体の一部として指定された定数を設定する(いわゆる即時アドレッシングモード)。コンパイラがconst int x = 5宣言の後にが続くとint a = x+x、2つのオプションがあります。

  • 変数であるかのように5をデータメモリに配置し、直接ロード命令を生成します。xへの書き込みをエラーとして扱う
  • xが参照されるたびに、値5の即時ロード命令を生成します

最初のケースではxアキュムレータレジスタへの読み取り、アキュムレータの場所での値の加算x、およびの場所へのストアが表示されaます。2番目のケースでは、5の即時ロード、5の即時追加、続いての場所へのストアが表示されaます。一部のコンパイラは、定数をそれ自体に追加し、に最適化a = x+xa = 10、の場所に10を格納する単一の命令を生成することを理解する場合がありaます。


1
+1は定数の折りたたみにも言及するため
jk。

10

必ずしも。またmyval、コンパイルされたコードではなく、そのままの値5を使用することもできます。

違い#define MYVAL 5とは、const int myval = 5プリプロセッサは、すでにすべての置き換えとして、前者の場合には、コンパイラは、一切の選択肢を持っていないことを言及しているMYVALと、ソースコードに5コンパイラがソースコードを見ることを得る時間で。後者の場合でも、選択肢があります。最適化されていないデバッグビルドの場合、コンパイラーは明示的にを割り当てますconst int。そのため、デバッガーではmyval、生の値5だけではなく、定数を確認できます。


定義するのではなく、constの利点を理解しています。しかし、constの例でも、値5は実行可能ファイルのどこかに格納されている必要がありますか?
user619818 2012

3
@ user619818、それは通常の変数/定数としてデータセグメントではなく、命令パラメーターとしてコード内に格納されます。
ペーテルTörök

@ user619818:命令には常にパラメーターがあります。したがって、別のストレージが割り当てられている場合、命令の直接の引数にその値アドレスがあります。(ARMなどの)固定命令サイズのCPUでは、5などの小さな定数が32ビット命令自体に収まるため、さらに悪化しますが、アドレスはそうではなく、余分なロードアドレス命令が発行されます。
Jan Hudec 2012

3

引用が言っていることは全く正しくありません。

優れたコンパイラーは、静的 const変数用のストレージを確保しません。const変数が静的ではなく、ファイルスコープ内にある場合、変数は別のコンパイルユニットから参照される可能性があるため、ストレージを確保しておく必要があります。リンク時の最適化では、リンカは可能性がある ストレージを排除し、変数を参照の指示を書き換えることができた場合、それはプログラムがその変数へのポインタを生成しないことを証明することができます。

const int代わりに使用するより良い理由#defineは、デバッガーがマクロを「参照」しないため#defined、デバッガーで 'd値を検査できないことです。


3

PéterTörökの回答から最初の文を盗みますが、詳しく説明し ます。必ずしもそうではありません。またmyval、コンパイルされたコードではなく、そのままの値5を使用することもできます。

myvalメモリーにスペースを割り当てることによって通常の変数のように処理すると、アーキテクチャーとメモリーの処理方法に応じて、非常に小さなものから深刻なものまで、パフォーマンスに影響を与える可能性があります。

そのように動作すると、コンパイラーは、「メモリー位置にあるものをレジスターRにロードする」という行に沿って何かを示す命令を発行しますmyval。の場所myval命令のオペランドとして、命令自体と同じデータブロックから直接取得されます。最近のCPUでは、この値は命令のプリフェッチにより、オンチップですぐに利用できます。アドレスを取得しても、CPUはメモリから値を取得する必要があります。場所がキャッシュ内で近くにある場合、それはすぐに行くかもしれませんし、そうでない場合、それほど速くは行かないかもしれません。CPUは値を取得するためにオフチップにする必要があるだけでなく、そうすることで、後で戻す必要のあるキャッシュから他のより有用なデータを押し出す可能性があります。メモリを仮想化するOSでプログラムを実行している場合、その場所へのアクセスによりページ違反が発生し、必要なページが周辺機器(ディスクなど)のI / Oを介してRAMに読み込まれるまでプログラムがスリープ状態になる可能性があります。

定数値をオブジェクトコードにハードワイヤリングすることにより、コンパイラは「レジスタRに値をロードする」などの命令を発行します5。上記のメモリアドレスと同様に、5は命令のオペランドであり、同じ方法で使用できます(つまり、プリフェッチされます)。CPUが5レジスタRに入れてビジネスに取り掛かるのに必要なものがすべて揃ったので、ここで類似点が終了します。通常、アドレスとレジスターは同じサイズであるため、命令が占めるバイト数に違いはなく、実際の実行は、メモリから何かを釣り出したときに発生する可能性のあるキャッシュミスやページフォールトの可能性がゼロです。

Péterが指摘したように、コンパイラーはmyvalデバッグビルド用にスペースとシンボルを割り当てることができます。これを行ってもその値をハードワイヤリングしても害はありません。値は何があっても同じままであり、シンボルは人間がデバッグで使用するために実際にそこにあるためです。

レジスタは本来整数であるため、これはレジスタに保持できる値にのみ適用されることに注意してください。他の定数はメモリに残ります。


1

変数 'myval'が使用されている場合は常に、コンパイラーは5を代入します。


0

コンパイラーはconst値を即値オペランドと見なします。イミディエートオペランドはデータストレージを必要としません。コンパイラは次のものを処理できます。

int foo = myVal;

と同じ

int foo = 5;

値5はデータメモリに格納されず、命令シーケンスの一部として格納されます。

値のアドレスが取得される可能性がある場合、コンパイラはデータストレージを予約する必要があります。その場合でも、myValの値が使​​用されると、コンパイラーは即時操作を引き続き使用します。

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