揮発性変数を宣言するとはどういう意味ですか?


9

多くの低レベルのプログラムは、しかし、私は一種のそれは何にとして困惑している、メモリマッピングなどのための種類の揮発性のキーワードを使用REALLYバックグラウンドで行います。つまり、コンパイラがメモリアドレスを「最適化しない」とはどういう意味ですか?


1
あなたは外にあなたの年齢を読んでいる場合はvolatile、変数と、それは5を言うと、あなたが来年再びそれを読んで、あなたは6取得することが保証している
5gon12eder

@ 5gon12eder、私は揮発性が何かが迅速かつ簡単に変更される可能性があることを意味すると理解していますが、それはどのように機能しますか?:S
Vikaton 2016年

また、コンパイルフラグによっては、不揮発性変数がデバッガーに表示されることがあります(たとえば、Cコード+ Eclipse + gdbを使用しているとします)。変数の値が次のようになっているため、 'optimized out value'レジスタのどこかに。アセンブリ言語のデバッグツール/機能の使用方法がわからない場合は、揮発性修飾子を使用して変数を宣言します。

回答:


11

volatile 他の何らかのプロセッサやI / Oデバイス、あるいは何かがあなたの下から変数を変更できることを意味します。

通常の変数では、プログラムのステップがそれを変更する唯一のものです。したがって、たとえば5、変数から読み取り、それを変更しない場合でも、変数にはが含まれます5。これを信頼できるので、次に変数を使用するときに、プログラムで時間をかけて変数を再度読み取る必要はありません。C ++コンパイラは、を記憶するだけのコードを生成するのに優れています5

しかし5、それをとして読み取ると、おそらくシステムがディスクからそのメモリにデータをロードし、に変更し500ます。プログラムに新しい値を読み取らせる500場合は、コンパイラーが以前に読み取った値を使いすぎないようにする必要があります5。毎回値をリロードするように指示する必要があります。それが何をするかvolatileです。

5歳児の例え
大きな紙をテーブルに置いたとします。紙の片隅に、進行中のゲームの現在のスコアを書き留めます3 to 4。次に、テーブルの反対側に行き、ゲームについてのストーリーを書き始めます。ゲームを見ている友達は、ゲームが進むにつれてそのコーナーのスコアを更新します。彼女は消し3 to 4書きします3 to 5

ゲームのスコアをストーリーに追加するときは、次のいずれかを行うことができます。

  1. あなたが読んだ最後のスコアを書き留めてください3 to 4。楽にそれが変化しなかった(または変化したかどうか気にしない)と仮定します、または
  2. テーブルの反対側に3 to 5歩き回り、現在のスコア(たまたま現在のスコア)を読み、戻ってください。これがvolatile変数の動作方法です。

11

volatile 2つのことを意味します。

  1. 変数の値は、コードを変更しなくても変更される場合があります。コンパイラは変数の値を読み取るしたがってたびに、それができるではない、それが読み込まれた前回と同じである、またはそれが格納された最後の値と同じであるが、それは再び読み出されなければならないことを仮定する。

  2. 揮発性変数に値を格納する動作は、外部から観察できる「副作用」であるため、コンパイラは値を格納する動作を削除できません。たとえば、2つの値が連続して格納される場合、コンパイラは実際に値を2回格納する必要があります。

例として:

i = 2; 
i = i; 

コンパイラー、数値2を保管し、変数iを読み取り、読み取った変数をiに保管する必要があります。

別の状況もあります。関数が使用setjmpしてからlongjmp呼び出された場合、関数のすべての揮発性ローカル変数には、最後の値が格納されることが保証されます。これは、不揮発性ローカル変数の場合とは異なります。


ここにはいくつかの微妙な問題があります。微妙な問題の1つは、揮発性読み取りが実際には変数へのアクセス方法の特性であるにもかかわらず、変数の特性として特徴付けられていることです。変数と値がある場合、からの読み取りを行いますが、その読み取りは揮発性のセマンティクスを持つことが保証されていません。ipi = &ix = *pii
Eric Lippert、2016年

1
@EricLippert:Ifはiとして宣言されvolatile int iた後piのように宣言する必要がありvolatile int *pi、その場合には、*piいや、揮発性のアクセスですか?
Jon Purdy 2016年

2

抽象説明
CもC ++も抽象マシンの概念を持っています。コードがある変数の値を使用する場合、抽象マシンは実装がその変数の値にアクセスする必要があると言います。フォームのコードは、statement_A; statement_B; statement_C;指定された順序どおりに実行する必要があります。これら3つのステートメントに共通する式は、出現するたびに再計算する必要があります。

抽象マシンごとに、ステートメントのシーケンスが与えられた場合statement_A; statement_B; statement_C;、実装は最初にstatement_A全体を実行し、次にを実行し、statement_B最後にを 実行する必要がありstatement_Cます。実装ではage、値5 を割り当てたことを思い出せません。参照するすべてのステートメントは、age代わりにその変数の値にアクセスする必要があります。

volatile実装が抽象マシン仕様に従ってCまたはC ++コードを厳密に実行する場合、キーワードは必要ありません。CおよびC ++の抽象マシンには、レジスタの概念、共通の副次式の概念はなく、実行順序は厳密です。

どちらの言語にもas-ifルールがあります。実装は、抽象マシン仕様に従って実行したかのように動作する限り、標準に準拠しています。コンパイラーは、不揮発性変数が割り当て間で値を変更しないと想定できます。as-ifルールに違反しない限り、シーケンスstatement_A; statement_B; statement_C;statement_C、の一部、次にの一部statement_A、次にのすべてstatement_B、残りのstatement_A、最後にの残りを実行することで実装できますstatement_C

これらのas-ifルールはvolatile変数には適用されません。volatile変数と関数に関しては、実装は、実行するように指示したとおりに、実行するように指示したとおりに実行する必要があります。

抽象マシン仕様には欠点があります。遅いです。他の言語と比較したCおよびC ++の良い点の1つは、非常に高速であることです。これは、これらの抽象マシンごとにコードが実行された場合には当てはまりません。AS-場合のルールはCとC ++は非常に高速であることを可能にするものです。

ELI5回答

コンパイラがメモリアドレスを「最適化しない」とはどういう意味ですか?

メモリアドレスを「最適化」することは高度な概念であり、5歳児の能力の範囲に含まれないものです。従順な5歳児は、あなたが言うように、それ以上、それ以下ではありません。を使用volatileすると、実装は5のように動作するように指示されます。代わりに、実装は、コードが指示するとおりに実行する必要があります。


1

(非)揮発性は、コンパイラーにコードを最適化する方法のヒントです(生成されたアセンブリコードの観点から)。

  • 非揮発性とは、現在のコンパイラーが変数の配置場所、または変数の値をサブルーチンに転送する方法を決定することを意味します
    • 固定記憶アドレスで
    • スタック上[プロセッサの現在のスタックポインタに対して]、
    • ヒープ上(プロセッサの現在のベースポインタに対して)、
    • プロセッサーレジスターで
    • ...
  • volatileは、main-cpu-s制御の外側にある何か(つまり、別のioプロセッサー)がこの値を変更できるため、コンパイラーが変数を最適化できないことを意味します。

0

答えはかなり一貫しているように見えますが、重要なポイントがありません。スペースを割り当て、すべてのアクセス(読み取りまたは書き込み)に対して、そのアクセスを実行するようコンパイラーに指示しています。何らかの理由でそれらのアクセスまたはその変数を最適化することを望まない。

はい、1つの理由は、他の誰かが私たちのためにその値を変更する可能性があるためです。別の理由は、他の誰かのためにその値を変更する可能性があることです。他の誰かが私たちのためにそれを変更するのか、私たちがそれを変更するのかは、ハードウェア/ロジックまたはソフトウェアかもしれません。これは、ハードウェアへの書き込みまたはハードウェアからの読み取りを行う、ベアメタル組み込みプログラムの制御およびステータスレジスタへのアクセスを定義するためによく使用されます。他の答えで説明されているソフトウェアと話すソフトウェアと同様に。

コードのセクションの時間を計ろうとしている場合に、アクセスが発生するタイミングと順序を制御するためにvolatileが使用されていることもわかります。また、volatileを使用しない場合は、問題の変数(開始時刻、終了時刻、差分)のみ​​を使用する必要があります。終わり近くに計算されたコンパイラーは、時間測定値のいずれかを(私たちが配置した場所ではなく)自由に移動できます。

時々、それは単に時間を燃やすために使用されるのを見るでしょう、エレメンタリーLEDウィンカー、ベアメタルのHello Worldは、人間の目がLEDを見るのに時間を費やすためだけに数に数える変数に揮発性を使用するかもしれません状態を変更します。タイマーやその他のイベントを使用して時間を消費する、より高度な例。

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