2

私はすでに質問の答えを通り抜けました @Cのconstとvolatileポインタの違いは何ですか? 私はその説明を理解しています:

const修飾子は、このコードが変数の値を変更できないことを意味しますが、このコードの外部の手段で値を変更できないことを意味するわけではありません。ただし、volatileは「このデータは他の誰かによって変更される可能性がある」と言っているため、コンパイラーはそのデータについて何も想定しません。

これは、両方のタイプの変数が外部イベントによって変更される可能性があることを意味します。

しかし、constとvolatileの使用法の違いはどこにありますか?

Cでは、コンパイラの最適化はconstで機能しますか?

4

6 に答える 6

3

volatile と const は多くの点で異なります。これらは 2 つの明確に異なる機能です。

const と同じように変数を宣言することは、「この変数がプログラムの外部で変更されることを期待しています」という意味ではありません。どこからそのアイデアを得たのかわかりません。const 変数がコード外で変更されることが予想される場合は、として宣言する必要があります。そうしないとvolatile const、変数が変更されないとコンパイラが想定する可能性があります。

デフォルトでは、単純な const 変数はあらゆる種類の変数と同様であり、プログラム自体によって変更することはできません。

単純な変数と同様に、const 変数の動作は、変数が宣言されているスコープに大きく依存します。ほとんどの場合、それらはファイル スコープで宣言され、静的ストレージ期間を持つ他の変数として動作しますが、(おそらく) メモリの別の場所に保存されます。それらがローカルスコープで宣言されている場合、それらが存在する関数が呼び出されると、時々変更される可能性があります。

そのため、const 変数が最適化されるケースはたくさんあります。一般的な最適化の 1 つに「文字列プール」があります。この場合、コンパイラは、同じ定数文字列リテラルがコード内に 2 回出現するかどうかをチェックし、同じアドレスを使用します。そのような文字列が外部ソースから変更されることを期待していたのに、それらを揮発性として宣言しなかったとしたら、奇妙なバグが発生するでしょう。

volatile 変数は、外部ソースによって変更される可能性がありますが、const 変数とは異なり、プログラムによって変更される可能性もあります。

于 2013-01-14T08:36:03.890 に答える
1

-qualified タイプのオブジェクトconstは、プログラムで宣言できる他のオブジェクトと同様のオブジェクトですが、それらを変更する権限がないという点だけが異なります。基礎となるオブジェクトは、たとえばエイリアスによって変更される可能性があり、そのようなイベントが発生した可能性がある場合、コンパイラは他のすべてのオブジェクトと同様に注意する必要があります。例えば

void toto(double const* pi, double* x) {
  printf("%g %g\n", *pi, *x);
  printf("%g %g\n", *pi, *x);
  *x = 5.0;
  printf("%g %g\n", *pi, *x);
}

ここでは、関数内で and so のtotoようなものを呼び出して、同じメモリを指すことはまったく問題ありません。2 番目の場合、コンパイラはとの値が変更されていないことをその間に保存しなかったため、想定できます。しかし、3 番目については、変更されたかどうかを予測できないため、メモリから値をリロードする必要があります。toto(&a, &a)pixprintf*pi*xprintf*pi

volatileそれとは違います。

void tutu(double volatile* pi, double* x) {
  printf("%g %g\n", *pi, *x);
  printf("%g %g\n", *pi, *x);
}

ここで、2 番目printfの場合、コンパイラは変更されていないと想定できます*xが、変更されている可能性があり、メモリから再読み込みする必要があると想定する必要があり*piますのユースケースは、日常のプログラマーの生活でははるかにまれであり、主にオブジェクトに関するものです。volatile

  • ハードウェアアドレスを表している可能性があります
  • 割り込みハンドラで変更される可能性がある
  • 何らかのsetjmp/longjmpメカニズムの下で
  • または別のスレッドで
于 2013-01-14T10:15:35.600 に答える
0

constを示す例

  function1()
  {
      int i = 10;
      function2(&i);
  }
 function2(int const *ptr) // usage of const
 {
      *ptr = 20; //will cause error; outside function can't be modify the value of i
 }

揮発性の例

 function1()
 {
       while(1)
       {
             i = 20;

              print(i);
       }
 }

 function2()
 {
       i = 20;
       while(1)
       {
              print(i);
       }
 }

これらの2つの機能を検討してください。どちらも同じようです。最適化コンパイラの場合、function1をfunction2に変換します。問題は、iの値が別のスレッドによって変更された場合、2つの関数が異なることです。ここでは、iのループ印刷値と別のモジュールがiの値を変更します。したがって、iの値が常に20になるとは限りません。

volatileは、変数を最適化しないようにコンパイラーに通知するために使用されます。

于 2013-01-14T09:11:56.160 に答える
0

'const' は、プログラムによっても、他の誰かによっても、値が決して変更されないことをコンパイラーに伝えます。何かが const の場合、コンパイラはそれに応じてコードを最適化し、通常は変数をコード内の定数に置き換えます。そのため、外部で変更されたとしても、プログラムは決して知らない可能性があります。

逆に、「volatile」は、変数がいつでも外部から変更できることをコンパイラーに伝え、コンパイラーは var をレジスターに入れるなどの最適化を実行しませんが、常にメモリーから読み取ります。かわった。

于 2013-01-14T08:50:35.227 に答える
0

const 修飾子は、このコードが変数の値を変更できないことを意味しますが、このコードの外部で値を変更できないことを意味するわけではありません。

const 修飾子を適用するには、2 つの異なる方法があります。

const で修飾されたオブジェクトをプログラムで変更してはなりません。そうしないと、プログラムの動作が未定義になります。const volatileオブジェクトは、OS/ハードウェアなどによって変更できますが、プログラムによって割り当てられることはありません。誤解を避けるために、const オブジェクトとは、その定義で const 型を使用するオブジェクトです。

const 修飾型へのポインターは、そのポインターを介した (コンパイル時の) 変更を防ぎますが、同じオブジェクトへの他のポインターを使用して変更することができます。オブジェクト自体が const でない場合、動作は定義されます。ただし、コンパイラは、OS/ハードウェア/必要なものによる任意の変更を考慮して、プログラムのみがオブジェクトを変更すると想定する場合がありますvolatile

非 const 修飾型へのポインターは、他のポインターによる変更に関する限り、const へのポインターとまったく同じです。

ただし、 volatile は、「このデータは、このプログラムのコード以外の何かによって変更される可能性がある」と述べているため、コンパイラは最適化時にそのデータについて何も仮定しません。

したがって、違いは次のとおりです。

#include <stdio.h>
void some_other_function(const int *);

int main() {
    int a = 0;
    int volatile b = 0;
    int const c = 0;
    int const *constptr = &a;
    int *ptr = (int*) constptr;

    printf("%d\n", a); // compiler can assume a == 0 at this point, and 
                       // replace the code with puts("0") if it wants to
    printf("%d\n", b); // compiler cannot assume a value for b, it's volatile[*]
    some_other_function(constptr); // defined in another TU
    printf("%d\n", a); // compiler can *no longer* assume that a == 0, 
                       // it might have changed
    *ptr = 1;          // there's another example of a changing, legally
    some_other_function(&c);
    printf("%d\n", c); // compiler can assume c == 0 because c is const
}

[*] 私は「値を想定できない」と言っていますが、仮想的な C 実装の中には、自動変数を検出するために必要な手段で変更する OS またはハードウェア メカニズムがないことをたまたま認識している可能性がありvolatileます。特にこの場合、への参照がb関数をエスケープしていません。もしそうなら、実装がvolatileこの特定のコードで実際に無視できることに気付くかもしれませんが、リンカが I/O ポートなどのアドレスにマップする手段を提供することを知っているため、extern グローバルvolatile変数を「適切に」扱う可能性があります。 .

于 2013-01-14T10:22:11.677 に答える