|
|
The previous examples have all used const because it's conceptually simpler. However, when using exact semantics is necessary, volatile should be used. To the programmer, volatile has multiple meanings. To a compiler writer it means to take no code generation shortcuts when accessing such an object. Moreover in ANSI C, it is a programmer's responsibility to declare every object that has the appropriate special properties with a volatile-qualified type.
The usual four examples of volatile objects are:
flag = 1; while (flag) ;is completely reasonable as long as flag has a volatile-qualified type. (Presumably, some asynchronous event will set flag to zero in the future.) Otherwise, the compilation system is free to change the above loop (because the value of flag is unchanged within the body of the loop) into a truly infinite loop that completely ignores the value of flag.
The fourth example, involving variables local to functions that call setjmp, is more involved. If you read the fine print about the behavior of setjmp and longjmp, you will find there are no guarantees about the values for objects matching the fourth case. It turns out to be necessary for longjmp to examine every stack frame between the function calling setjmp and the function calling longjmp for saved register values in order to get the most desirable behavior. The possibility of asynchronously created stack frames makes this expensive job even harder. Therefore, most implementations just documented the undesirable side effect and used an inexpensive implementation.
When an automatic object is declared with a volatile-qualified type, the compilation system knows that it has to produce code that exactly matches what the programmer wrote. Therefore, the most recent value for such an automatic object will always be in memory (not just in a register) and as such will be guaranteed to be up-to-date when longjmp is called.