5 に答える
このvolatile
キーワードは、関数ではなくストレージを表すオブジェクトに適用されるように設計されています。関数から a を返すvolatile int
ことはあまり意味がありません。関数の戻り値は最適化されず (インライン化された関数は例外となる可能性がありますが、それはまったく別のケースです...)、外部アクターがそれを変更することはありません。関数が戻るとき、戻り値のコピーを呼び出し元の関数に渡します。volatile
オブジェクトのコピーはそれ自体ではありませんvolatile
。したがって、volatile int
will を返そうとするとコピーが作成され、それが non-volatile にキャストされ、int
コンパイラ メッセージがトリガーされます。を返すvolatile int*
と便利かもしれませんが、volatile int
.
関数に値でオブジェクトを渡すと、オブジェクトのコピーが作成さvolatile int
れるため、関数パラメーターとして a を使用すると、必ず修飾子を無視する変換が必要になります。volatile をアドレスで渡すことは完全に合理的ですが、値ではできません。
C 仕様によると、 の動作volatile
は完全に実装に依存するため、YMMV.
この方法を使用volatile
して、ある種のコンパイラの最適化を無効にしようとしていますか? もしそうなら、おそらくそれを行うためのより良い方法があります。
編集:
質問の更新を考慮すると、別の方法でこれにアプローチできるようです。コンパイラの最適化を無効にしようとしている場合は、直接的なアプローチを取り、単にコンパイラに最適化しないように指示してみませんか? #pragma GCC optimize
またはを使用__attribute__((optimize))
して、関数に特定の最適化パラメーターを指定できます。たとえば__attribute__((optimize(0)))
、特定の関数のすべての最適化を無効にする必要があります。そうすれば、データ型を非揮発性に保ち、発生している型の問題を回避できます。すべての最適化を無効にするのが少し多すぎる場合は、その属性/プラグマを使用して個々の最適化オプションをオンまたはオフにすることもできます。
編集: 警告やエラーなしで次のコードをコンパイルできました:
static int functionTwo(int *number) {
return *number + 1;
}
typedef union {
int i;
volatile int v;
} fancy_int;
int main(void) {
fancy_int count;
count.v = 10;
count.v = functionTwo(&count.i);
return 0;
}
このハック「テクニック」にはおそらく何らかの奇妙な副作用があるため、本番環境で使用する前に十分にテストしてください。ほとんどの場合、アドレスを に直接キャストするのと同じですが(int*)
、警告は発生しません。
ここで私がベースから外れている可能性がありますが、揮発性は通常スタックメモリ領域に関連付けられているものではありません。したがって、次のプロトタイプが本当に意味があるかどうかはわかりません。
volatile int functionOne(volatile int number);
返された整数が揮発性になる方法がわかりません。EAX の値が変化する原因は何ですか? 同じことが整数にも当てはまります。値がスタックにプッシュされてパラメーターとして渡されると、何がその値を変更するのでしょうか?
volatile
関数の戻り値の型に修飾子を付けたい理由がわかりません。関数の戻り値を割り当てる変数は、volatile
代わりに a として入力する必要があります。
これらの変更を行ってみてください:
typedef int COUNT_TYPE;
typedef volatile COUNT_TYPE COUNT;
COUNT_TYPE functionOne( COUNT number );
COUNT_TYPE functionTwo( COUNT_TYPE number );
を呼び出すときfunctionTwo()
は、引数を明示的にキャストします。
functionTwo( (COUNT_TYPE)arg );
HTH、アシッシュ。
私がコンパイルすれば
typedef volatile int COUNT;
static int functionTwo(int number) {
return number + 1;
}
int main(void) {
COUNT count = 10;
count = functionTwo(count);
return 0;
}
使用して
gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wextra -Wstrict-prototypes -Wmissing-prototypes foo.c
警告は表示されません。gcc 4.0、4.2、4.3、および 4.4 を試しました。あなたの warningTwo は、値ではなくポインタを渡しているように聞こえますが、それは別の話です...
編集:
あなたの最新の例は次のように書かれるべきです。繰り返しますが、警告はありません:
typedef volatile int COUNT;
static int functionTwo(COUNT *number) { return *number + 1; }
int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; }
編集:
functionTwo を変更できない場合:
typedef volatile int COUNT;
static int functionTwo(int *number) { return *number + 1; }
int main(void) {
COUNT count= 10;
int countcopy = count;
count = functionTwo(&countcopy);
return 0;
}
volatile 変数へのアクセスはすべて「特別」であることに注意してください。を含む最初のバージョンではfunctionTwo(COUNT *number)
、functionTwo はそれに適切にアクセスする方法を知っています。countcopy を使用した 2 番目のバージョンでは、メイン関数は countcopy = copy を割り当てたときに適切にアクセスする方法を認識しています。
それを書いた人は、すべての操作がアトミックであることを確認したくて、すべての int 変数を volatile として宣言した可能性があります (同期が不十分な MT アプリケーションですか?)。そのため、コードのすべての int は volatile として宣言されています一貫性"。
あるいは、関数型を揮発性として宣言することで、純粋な関数の繰り返し呼び出しの最適化を停止することを期待しているのでしょうか? 関数内の静的変数をインクリメントすると解決します。ただし、これでは意味がありませんので、本来の意図を推測してみてください。