Zephyr Cradle Diary


2009.05.28 (Thu)

[PG] volatile(C言語)

話題に困ってかつCDのレビューを書く気力もないときは適当にプログラミング話を綴っていけば良いんじゃないかと閃いた次第。まあ基本はやっぱりC言語になっちゃうんですけど。しかも初歩的な話だったりしますが。

そんなわけで、volatileです。

volatileって、あんま使わないですよね。たぶんVCとかで開発やってる限り、ほっとんどお世話にならないのではないかと。そもそもマルチスレッドプログラミングなんていきなりやらされることもなく、そんな理由からも新人研修とかでも飛ばされたりして。でも知らないと困るときが絶対的にあります。マルチスレッドプログラミングが必要なときですね。

volatileってのが何をするかっていうと、コンパイル時の最適化を抑止します。最適化ってのは、例えば変数aに0を代入して、次のステートメントで即座に変数aに100を代入するような処理だったりすると、

int a;

a = 0;

a = 100;

コンパイルしたときに処理が最適化されて、次みたいに丸められちゃうんですね。だって同じ意味ですし。(Optimizeのコンパイルオプションにもよりますが。)

int a = 100;

ただ、そうなられると困るときがあります。それは、この変数aを、別の処理で参照してたりするときですね。そういう、この「aに0を入れてから100を入れるっていう手続きと順番が大事なんだよ!」っていうときが往々にしてあります。例えばこのaがグローバル変数だったり共有メモリ直参照だったりなとき。そんなときに勝手に処理をまとめられると、ひじょーに困ります。

そんなときに登場するのが、このvolatileちゃんです。あ、ちなみに「ぼらたいる」って読みます。ボラで鯛でるー☆です。先のコードは以下のように書くと、最適化される心配はありません。ちゃんと順番通りになってくれます。

volatile int a;

a = 0;

a = 100;

ただちょっと注意してもらいたいのが、これは「volatile int」型になってしまい、さっきまでの「int」型とは別の変数型だという点。例えばこの変数を別の関数のint型引数をとるパラメータに渡すときは、環境によってはint型にキャストして渡さないとWarningを吐かれる場合があります。まあビルドしてみれば一発で判るので注意ってほどでもないですけどね。

ちなみに、ポインタでも同じです。構造体やクラスでも同じです。構造体にvolatileを付けた場合、そのメンバ全てが最適化対象外になります。なので最適化を避けたいメンバが複数在る場合は、ある程度カテゴライズしてクラスなりに固めておいたほうが圧倒的に便利かと思います。

当方が職場でやってる組み込みなんかだと、構造体ポインタ型を宣言してアドレスに即値を与えて、そこから共有メモリに直接アクセスするなんてことがままあります。こういう構造体ポインタ型にはvolatileを付けておいたほうが何かと困らないことが多いですね。

ただし多用は禁物です。最適化を抑止するわけですから、当然ビルドして出来るオブジェクトファイル、実行ファイルは大きくなります。そこは実用性とトレードオフで決めた方が良いでしょうね。共有メモリを直接参照する系の処理には、まず間違いなく付けておいて損はないと思いますが。

そんな感じで、volatileのお話でした。