C言語のvolatile型修飾子とコンパイラの最適化について

昔、先輩に教えてもらったC言語のvolatile型修飾子の説明がわかりやすかったので記載しておく。なおコードはかなり単純化している。

下記のようなプログラムがあった時

unsigned int *ioAddr = (unsigned int *)0x00FFEFFF;

*ioAddr = 0x00000001; //①
*ioAddr = 0x00000002; //②
*ioAddr = 0x00000004; //③

ここで ioAddr の接続先を、例えばメモリマップドI/Oで接続された外部ハードウェア装置などと想定した場合、ハードウェアにとっては①、②、③の書き込みは全て必要不可欠な操作であるとする。

ところがソフトウェア的に見れば *ioAddr は③により最終的に4に確定するので①と②の書き込みは不要に見える。そのためコンパイラによっては①と②のコードは最適化により削除される可能性がある。そうするとハードウェアは正常に動作しなくなってしまう。

このような時は ioAddr を最適化の対象から除外する必要がある。この時に指定するのがvolatile型修飾子である。

//volatileを指定
volatile unsigned int *ioAddr = (unsigned int *)0x00FFEFFF;

*ioAddr = 0x00000001; //①
*ioAddr = 0x00000002; //②
*ioAddr = 0x00000004; //③

とすることにより、*ioAddr に対する操作は最適化されず、上記のプログラムで言えば①、②及び③のコードが全て実行されるようになる。

コメント