違い

2011-01-04 1 views
61

我々はその変数の値が続いて違い

​​
変更されることはありませんconstとして変数を宣言すると、私たちはvolatileとして新鮮な値が
に更新されるたびに、変数を宣言する場合上記のように変数tempを宣言するのは何ですか?
const int tempと宣言するとどうなりますか?

+0

あなたは 'constの揮発性を使用していないだろうint temp; 'ブロックスコープ(つまり、' {} 'の内側)では、そこには使用されません。 –

答えて

21

2つのシーケンスポイント間で変数が変更されていない可能性があるため、変数ではありません。

コンストレインスは、値を変更しないことを約束します。値は変更されません。

+5

さらに、 'const'データが「定数」ではないことを指摘するためのものです。 –

24
  • volatileは、変数を関連付けるコードを最適化しないようにコンパイラに指示します。通常、変数が「外部」から変更可能であることがわかっている場合などです。別のスレッドによって。
  • constは、プログラムが変数の値を変更することが禁止されていることをコンパイラに通知します。
  • const volatileは、あなたの人生(tm)で正確に0回使用されていると思われる非常に特殊なものです。予期されるように、プログラムが変数の値を変更することはできませんが、値は外部から変更できるため、変数に対して最適化は行われません。
+8

私は 'volatile '変数は通常、ハードウェアを使い始めたときに何が起きるのだろうと思っていました。他のスレッドではありません。私が見た 'const volatile'は、メモリマップ状態レジスタなどのようなものです。 –

+2

もちろん、あなたは絶対に正しいですが、マルチスレッドは単なる例ではありますが、唯一の例ではありません。 – mingos

+13

組み込みシステムで作業する場合、これは非常に頻繁に表示されます。説明のために –

95

const volatileが(エラーが原因const修飾子に上昇する)コードによって変更されることが許可されないようにマークされたオブジェクト - 少なくともその特定の名前/ポインタを介し。

修飾子の一部は、コンパイラがオブジェクトへのアクセスを最適化または並べ替えることができないことを意味します。

組み込みシステムでは、これは通常ハードウェアによって読み取られ更新されるハードウェアレジスタにアクセスするために使用されますが、書き込みには意味がありません(書き込みにエラーが発生する可能性があります)。

例として、シリアルポートのステータスレジスタがあります。文字が読み込みを待っている場合、または送信レジスタが新しい文字を受け入れる準備ができている場合(つまり、空の場合)、さまざまなビットが表示されます。このステータスレジスタを読み取るごとに、シリアルポートハードウェアに何が発生したかによって、異なる値が返される可能性があります。

ステータスレジスタに書き込む意味はありませんが(特定のハードウェア仕様によって異なります)、レジスタの読み込みごとにハードウェアの実際の読み込みが行われることを確認する必要があります。以前の読み取りでは、ハードウェアの状態の変更については教えられません。

簡単な例:これらのポインタがvolatileあるものとしてマークされていなかった場合は

unsigned int const volatile *status_reg; // assume these are assigned to point to the 
unsigned char const volatile *recv_reg; // correct hardware addresses 


#define UART_CHAR_READY 0x00000001 

int get_next_char() 
{ 
    while ((*status_reg & UART_CHAR_READY) == 0) { 
     // do nothing but spin 
    } 

    return *recv_reg; 
} 

、夫婦の問題が発生する可能性があります:

  • をwhileループのテストは以来、一度だけ、ステータスレジスタを読むかもしれませんコンパイラはそれが何を指しても決して変わらないと仮定することができます(whileループテストやループ自体を変更することはできません)。UARTハードウェアで待機中の文字がないときに関数を入力した場合、文字が受信されても​​停止しなかった無限ループに終わることがあります。
  • ループで*recv_regが変更されたことを示す関数が何もないので、受信レジスタの読み込みをコンパイラによってwhileループの前に移動することができます。ループ。

volatile修飾子は、これらの最適化が確実にコンパイラによって実行されないようにします。

+0

+1。私は疑問があります:const volatileメソッドはどうでしょうか?私のクラスの中には多くのスレッドがアクセスしていますが(アクセスはmutexと同期していますが)、constメソッドもvolatileでなければなりません(他のスレッドによって変数が変更される可能性があるので) – Sasa

6

これは、ブートローダによって更新できるフラッシュメモリの領域にいくつかの設定変数がある組み込みアプリケーションで使用する必要がありました。一定の値を事前に計算し、即時のアセンブリ命令を使用して、またはロードすることにより、...これらの設定変数は、実行時に「定数」でありますが、揮発性の修飾子なしでコンパイラは、このような何かを最適化するだろう...

cantx.id = 0x10<<24 | CANID<<12 | 0; 

近くの場所から一定の値に変更されるため、設定フラッシュ領域内の元のCANID値の更新は無視されます。 CANIDはconst volatileでなければなりません。

3

constは、変数がcコードで変更できないことを意味し、変更できないことを意味しません。つまり、変数に書き込む命令はありませんが、その値は変わる可能性があります。

volatileは、変数がいつでも変更される可能性があり、したがってキャッシュされた値は使用されないことを意味します。変数への各アクセスは、そのメモリアドレスに対して実行されなければならない。

(これらは通常別.hファイルで処理されているので)質問タグ付けされた「組み込み」とtempを想定しているが、ユーザは変数ではなく、ハードウェア関連のレジスタを宣言されているので、検討:

組み込みプロセッサデータおよびプログラム空間が共通のデータおよびアドレスバスを共有するフォンノイマン(Flon)メモリのような揮発性読み出し - 書き込みデータメモリ(RAM)および不揮発性読み出し専用データメモリの両方を有する。

あなたが値を(少なくとも0と異なる場合)持っているconst tempを宣言した場合、それがRAMアドレスに割り当てられたとしても、それはまだフラッシュメモリを必要とするため、コンパイラは、FLASH空間のアドレスに変数を割り当てますが変数の初期値を格納するため、すべての操作が読み込み専用であるため、RAMアドレスはスペースの無駄になります。結果は

int temp;

スタートアップ(CSTART)で0に初期化し、RAMに格納された変数であり、キャッシュされた値を使用することができます。

const int temp;は、(読み取り専用)FLASHに格納され、コンパイル時に0に初期化された変数です。キャッシュされた値が使用されます。

volatile int temp;はRAMに格納された変数で、起動時に0に初期化されます(cstart)。キャッシュされた値は使用されません。

​​は、コンパイラの時に0に初期化(読み込みONY)をFLASHに格納された変数で、キャッシュされた値は、ここで

を使用されることはありません便利部分来る:

を今日では、ほとんどの組み込みプロセッサは持っています特殊機能モジュールを使用して読み取り専用の不揮発性メモリに変更を加える能力。この場合、実行時にconst int tempを変更することができます。直接変更することはできません。言い換えれば、関数はtempが格納されているアドレスの値を変更することができます。

実際の例では、デバイスのシリアル番号としてtempを使用します。組み込みプロセッサーが初めて実行されるときには、tempは0(または宣言された値)に等しくなり、関数はこのファクトを使用して製造中にテストを実行し、sucessfullの場合はシリアル番号を割り当ててtemp特別な機能によって一部のプロセッサには、そのためのOTP(ワンタイムプログラマブル)メモリを備えた特別なアドレス範囲があります。 const int tempが新しいことを意味、キャッシュされた値は、次のブート刚性使用されるかもしれません、代わりにワンタイムプログラマブルシリアル番号の変更可能なIDであり、volatileを宣言されていない場合

しかし、ここでは違いが来ます次回の再起動、またはさらに悪いことに、新しい値を使用する機能もあれば、再起動するまで古いキャッシュ値を使用する機能もあります。 const int tempvoltaileと宣言されている場合、IDの変更は直ちに有効になります。

1

。変数 'c​​onst volatile'を宣言しているときには、変数を変更しないようにプログラムに指示しています。この変数は、外部からの入力から予期せず変更することができます。

+0

この答えは ' volatile指定子はまったくありません。 –

4

Cでは、constとvolatileは型修飾子であり、これら2つは独立しています。

基本的にconstは、値がプログラムによって変更できないことを意味します。

volatileは、値が突然変更される可能性があることを意味します(おそらく、プログラムの外側から)。

実際、C標準では、constとvolatileの両方の有効な宣言の例が記述されています。例は

「のextern constの揮発性INT real_time_clock;」であるreal_time_clockは、ハードウェアによって変更可能であってもよいが、それに割り当てられたインクリメント又はデクリメントすることができない

私たちはすでにconstとvolatileを別々に扱っています。また、これらの型修飾子はstruct、union、enum、typedefにも適用されます。

2

constとvolatileを一緒に使用できます。例えば0x30のが唯一の外部条件によって変更されたポート の値であると仮定した場合、次の宣言は、いずれかの可能性が不慮の副作用の を防止するであろう:

const volatile char *port = (const volatile char *)0x30;