これまでの例では、const は概念的に単純なものとして示されてきました。しかし、volatile はどのような意味でしょうか。それはコンパイラにとって、そのようなオブジェクトへのアクセス時にコード生成上のショートカットを行ってはいけない、ということを意味します。一方、ISO C では、対応する特殊な特性を持つすべてのオブジェクトを volatile として宣言することはプログラマの責任としています。
volatile は、通常、次の 4 つのオブジェクトに使用します。
メモリーにマップされた入出力ポートであるオブジェクト
複数の並行プロセス間で共有されるオブジェクト
非同期シグナルハンドラによって変更されるオブジェクト
setjmp を呼び出す関数中で宣言され、その値が setjmp への呼び出しとそれに対応する longjmp への呼び出し間で変更される自動記憶オブジェクト
最初の 3 つの例はすべて、特定の動作を行うオブジェクトのインスタンスです。つまり、その値は、プログラムの実行中の任意の時点で変更できます。したがって、一見無限ループに見える次のループは、flag が volatile で修飾された型を持つかぎりにおいて有効となります。
flag = 1; while (flag);
おそらく、ある非同期イベントが将来 flag をゼロに設定することもあります。volatile 修飾型を持たない場合、flag の値はループ本体内では変更されないため、コンパイルシステムによって前述のループは、完全に flag の値を無視する本当の無限ループに変更されることもあり得ます。
4 番目の例は、setjmp を呼び出す関数に対して局所的な変数を含んでいるため、より複雑です。setjmp と longjmp の動作に関する詳細は、4 番目の例に一致するオブジェクトの値は予測不可能であることを示します。もっとも望ましい動作を行うためには、longjmp が、setjmp を呼び出す関数と longjmp を呼び出す関数の間で、保存されたレジスタ値に対してすべてのスタックフレームを検査する必要があります。スタックフレームは非同期的に作成される可能性があるため、この作業はより難しくなります。
自動オブジェクトが volatile 修飾型で宣言される場合、コンパイラは、プログラマが書いたものと完全に一致するコードを生成する必要があります。したがって、このような自動オブジェクトに対する最新の値は、レジスタ内だけでなく常にメモリー内にあり、longjmp が呼び出されたときに最新であることが保証されます。