C言語の勉強をやり始めて二か月の者です。
volatileの意味が分からないのですが、分かりやすい具体例とかありましたら、よろしければ
教えて頂きたいです。
参考書やネットを使って調べているのですが、なかなか理解できません。
以上、宜しくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答6件
0
ベストアンサー
volatileの意味が分からないのですが、分かりやすい具体例とかありましたら、よろしければ
教えて頂きたいです。
あなたが想定する対象環境により回答が変わります:
- 組み込み系の場合:IOポートなど外部デバイスと通信するケースで、メモリアドレスを介して入出力を行うときに
volatile
が必要となります。 - 上記以外の普通のOSの場合:(少々乱暴な言い方ですが)
volatile
の正しい意味を理解するまでは、それを使わないでください。通常のプログラムでは必要にならない機能です。
また、Intenet上には「マルチスレッドプログラムではvolatile
が必要だ」という情報もいくつかみられますが、C言語においては誤った情報です。
- C言語ではなくJava言語の話をしている可能性があります。CとJavaではvolatileは意味が全く異なります。(=Javaでは正しい情報ですが、Cには適用できない)
- 古いC言語仕様と古いコンパイラでは、volatileが必要な時代もありました。(=当時は正しかったが、今となっては陳腐化してしまった)
自分向けに書いた内容ですが volatile変数とマルチスレッドとの関係 で詳しく解説しています。(他人に説明するトーンで書いてないので全体的に言葉足らずですが)
投稿2016/07/04 09:18
編集2016/07/04 09:22総合スコア6191
0
volatile の英語の意味は「気まぐれな、移り気な」(http://eow.alc.co.jp)があるそうです。
つまり、「値が勝手に変わってしまう」変数に対して volatile を宣言します。
「値が勝手に変わってしまう」って、そんなことあるの?あったらプログラムは正しく動かないんじゃ?
と思うでしょうが、あるんです。
典型的には組み込みのシステムで使われる、機械の状態を示す変数(レジスターなどと呼ばれます)です。
例えば、
「ボタンを押している/離している」を「押している = 1」、「離している = 0」とすると、
人間がボタンを操作するごとに、プログラムとは無関係に値が変わります。
この時、ttyp03 さんの回答のように、最適化されていると、0 → 1 の変化をプログラムが
検出できません。
このような事が起こらないように volatile とします。
投稿2016/07/04 01:23
総合スコア711
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
解決済みになっていますので、蛇足になるかと思いますが、volatile は割り込みハンドラを使ったプログラミングでも使用します。
C
1// SIGTERM の割り込みハンドラに terminate() を設定 2.. 3volatile int shutdown = 0; 4while(shutdown == 0){ 5 処理 6} 7 8// シャットダウン割り込みハンドラ 9void terminate(){ 10 if (shutdown == 0) { 11 //終了処理 12 shutdown = 1; 13 } 14}
というような場合に変数 shutdown を volatile 宣言しておかないと、割り込みハンドラの中で shutdown を正しく参照できません。理由はここまでの議論の通り、処理の実行中に割り込みが発生してハンドラの中から shutdown を参照してもコンパイラの最適化で shutdown の値がメモリに書き込まれていない可能性があるからです。
投稿2016/07/13 01:51
総合スコア3401
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
volatile 理解するの苦しみますよね。
結論から言うと volatileは コンパイラ最適化オプションを有効にした上で
最適化対象としたくない変数操作がある変数に対して適用します。
以下、補足説明です。
コンパイラには 最適化オプションというのがあって、
最適化が有効になっていると、定義した変数を利用しないと、不要なコードとして取り扱われ
アセンブラレベルのコードが生成されなくなるケースがあるのです。
例えば
int *a = (int *)0x100000; // 読み対象レジスタのアドレスを0x100000と仮定 void func() { int *b; b = a; // #1 /* 変数bを利用するコードを書かない */ }
上記のサンプルは、変数bが参照されないので、最適化オプションが有効時は、
#1に相当するアセンブラコードが生成されません。
(アセンブラコードを生成するにはお使いのコンパイラのオプションを調べてください)
※ 最適化オプションが無効な場合は、#1に相当するアセンブラコードも生成されます。
ところが、
変数に値を代入する操作(具体的にリード)だけでも意味をもつ場合あります。
特に組込プログラミングにおいては レジスタ値を読むということだけでも意味がある場合があります。
その場合は次の様に記述することになります。
int *a = (int *)0x100000; // 読み対象レジスタのアドレスを0x100000と仮定 void func() { volatile int *b; b = a; // #1 /* 変数bを利用する事がない */ }
上記の場合、最適化オプションが有効な場合でも#1に相当するアセンブラコードは生成されます。
常に最適化オプション無効としてコンパイルするならこんな考慮は必要ないのですが
組込プログラミングにおいては、対象となるハードウエアはPC程の多くのメモリを積んでいないので
可能な限りメモリ使用量を減らしたいケースが殆どなので、
最適化オプション有効+必要に応じてvolatile宣言
というケースが多いです。
ちょっと長くなりましたが、ポイントつかんで頂けたでしょうか。
投稿2016/07/04 02:15
編集2016/07/04 03:01総合スコア14
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
volatile修飾子とはコンパイラによる最適化を抑制するための修飾子です。
最適化というのは無駄がコードを無駄のないコードに置き換えることです。たとえば以下のような変数xに1を足す処理を3回繰り返すコードがあるとします
int x = 0;
x += 1;
x += 1;
x += 1;
しかしこれはxに1回3を足したコードと同じなのでコンパイラは
int x = 0;
x += 3に置き換えてくれます。
そこでvolatileを付けると最適化をさせずに1を3回足したコードのままコンパイルしてくれるようになります。
普通なら最適化してくれた方がありがたいので使いどころが無いように見えますが、最適化されて困る場合もあるのでそのときに使います。
例えばまだご存じないかも知れませんが、マルチスレッドで並列処理をするとき片方の処理が終わるのを待つときこのように書く場合があります。
while(wait){
Sleep(1);
}
//別スレッド
void another_thread(){
//何か処理
wait = false;
}
これはwhile文とanother_thread()関数は同時に動いている状況です。
このときwhile文の方はwaitがtrueであるときループを抜けずに永久にループし続けます。
そして裏で動いているanother_thread()関数でwaitがfalseになるとループを抜けて動き出します。
このようにしてanother_thread()関数内で処理が終わるまで確実に待つことができるのです。
さて本題ですがコンパイラからするとこのコードはwhile文内でwaitは一度も変化しません。
while(wait){
Sleep(1);
}
しかしwhile文は毎回分岐処理をしますので1度も変化のない変数を毎回判定するのは無駄と考えます。
すると以下のコードに書き換えます
if(wait){
while(1){
Sleep(1);
}
}
最初に1回だけif文で判定してその後はwhile(1)で永久にループする無駄のないコードになりました。
しかしこれは意図通りの動きはしてくれませんね、裏でwaitを書き換えてもループを抜けることができません。
そこでwaitにvolatileを付けることで、この変数は最適化しなくてもいいよとコンパイラに教えることで解決することができるようになります。
そのほかにも組み込みなんかでレジスタではなく確実にメモリに値を書き込んでほしいときにも使ったりします。
まあこれらは今後使うようになるかもしれないことなので今は頭の片隅に置いといてください。
投稿2016/07/04 01:48
総合スコア19
0
簡単に言えばコンパイラによる最適化を抑止する
でしょうか。
下記サイトにはわかりやすい例が載っていました。
http://proger.blog10.fc2.com/blog-entry-20.html
投稿2016/07/04 01:04
総合スコア17000
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/04 10:07 編集
2016/07/04 10:29
2016/07/04 12:04
2016/07/05 01:46