manpagez: man pages & more
info autoconf
Home | html | info | man

File: autoconf.info,  Node: Volatile Objects,  Next: Floating Point Portability,  Prev: Buffer Overruns,  Up: Portable C and C++++

13.6 Volatile Objects
=====================

The keyword ‘volatile’ is often misunderstood in portable code.  Its use
inhibits some memory-access optimizations, but programmers often wish
that it had a different meaning than it actually does.

   ‘volatile’ was designed for code that accesses special objects like
memory-mapped device registers whose contents spontaneously change.
Such code is inherently low-level, and it is difficult to specify
portably what ‘volatile’ means in these cases.  The C standard says,
"What constitutes an access to an object that has volatile-qualified
type is implementation-defined," so in theory each implementation is
supposed to fill in the gap by documenting what ‘volatile’ means for
that implementation.  In practice, though, this documentation is usually
absent or incomplete.

   One area of confusion is the distinction between objects defined with
volatile types, and volatile lvalues.  From the C standard's point of
view, an object defined with a volatile type has externally visible
behavior.  You can think of such objects as having little oscilloscope
probes attached to them, so that the user can observe some properties of
accesses to them, just as the user can observe data written to output
files.  However, the standard does not make it clear whether users can
observe accesses by volatile lvalues to ordinary objects.  For example:

     /* Declare and access a volatile object.
        Accesses to X are "visible" to users.  */
     static int volatile x;
     x = 1;

     /* Access two ordinary objects via a volatile lvalue.
        It's not clear whether accesses to *P are "visible".  */
     int y;
     int *z = malloc (sizeof (int));
     int volatile *p;
     p = &y;
     *p = 1;
     p = z;
     *p = 1;

   Programmers often wish that ‘volatile’ meant "Perform the memory
access here and now, without merging several memory accesses, without
changing the memory word size, and without reordering."  But the C
standard does not require this.  For objects defined with a volatile
type, accesses must be done before the next sequence point; but
otherwise merging, reordering, and word-size change is allowed.  Worse,
it is not clear from the standard whether volatile lvalues provide more
guarantees in general than nonvolatile lvalues, if the underlying
objects are ordinary.

   Even when accessing objects defined with a volatile type, the C
standard allows only extremely limited signal handlers: in C99 the
behavior is undefined if a signal handler reads any non-local object, or
writes to any non-local object whose type is not ‘sig_atomic_t
volatile’, or calls any standard library function other than ‘abort’,
‘signal’, and ‘_Exit’.  Hence C compilers need not worry about a signal
handler disturbing ordinary computation.  C11 and Posix allow some
additional behavior in a portable signal handler, but are still quite
restrictive.

   Some C implementations allow memory-access optimizations within each
translation unit, such that actual behavior agrees with the behavior
required by the standard only when calling a function in some other
translation unit, and a signal handler acts like it was called from a
different translation unit.  The C99 standard hints that in these
implementations, objects referred to by signal handlers "would require
explicit specification of ‘volatile’ storage, as well as other
implementation-defined restrictions."  But unfortunately even for this
special case these other restrictions are often not documented well.
This area was significantly changed in C11, and eventually
implementations will probably head in the C11 direction, but this will
take some time.  *Note When is a Volatile Object Accessed?:
(gcc)Volatiles, for some restrictions imposed by GCC. *Note Defining
Signal Handlers: (libc)Defining Handlers, for some restrictions imposed
by the GNU C library.  Restrictions differ on other platforms.

   If possible, it is best to use a signal handler that fits within the
limits imposed by the C and Posix standards.

   If this is not practical, you can try the following rules of thumb.
A signal handler should access only volatile lvalues, preferably lvalues
that refer to objects defined with a volatile type, and should not
assume that the accessed objects have an internally consistent state if
they are larger than a machine word.  Furthermore, installers should
employ compilers and compiler options that are commonly used for
building operating system kernels, because kernels often need more from
‘volatile’ than the C Standard requires, and installers who compile an
application in a similar environment can sometimes benefit from the
extra constraints imposed by kernels on compilers.  Admittedly we are
hand-waving somewhat here, as there are few guarantees in this area; the
rules of thumb may help to fix some bugs but there is a good chance that
they will not fix them all.

   For ‘volatile’, C++ has the same problems that C does.  Multithreaded
applications have even more problems with ‘volatile’, but they are
beyond the scope of this section.

   The bottom line is that using ‘volatile’ typically hurts performance
but should not hurt correctness.  In some cases its use does help
correctness, but these cases are often so poorly understood that all too
often adding ‘volatile’ to a data structure merely alleviates some
symptoms of a bug while not fixing the bug in general.

© manpagez.com 2000-2025
Individual documents may contain additional copyright information.