Introduction to Systems Programming
const - Sec. 18.3, Type Qualifiers, and
examples on pp. 172, 250-251, 254-255, 265-266, 478-479
volatile - Sec. 20.3, Other Low-Level
Techniques, pp. 523-524
restrict- Sec. 17.8, Restricted Pointers, and
the example on p. 543
- Sec. 4.4.3, Type qualifiers
Sec. 4.4.4, Const
Sec. 4.4.5, Volatile and Sequence Points (pp.
93-94, see class handout)
Sec. 4.4.6, Restrict
- Sec. 7.1, Objects, Lvalues and Designators
An object (in C) is a
region of memory that can be examined and stored into.
An lvalue is an expression
that refers to an object in such a way that the object may be
examined or altered.
Legal lvalue expressions in C
- Only an lvalue can appear on the left side of an assignment
- A modifiable lvalue
is an lvalue that permits modification of the designated object.
- The formal definition in the C Standard is
- An lvalue is an
expression (with an object type other than
that potentially designates an object; if an lvalue does not
designate an object when it is evaluated, the behavior is
undeﬁned. When an object is said to have a particular
type, the type is speciﬁed by the lvalue used to designate the
object. A modiﬁable
lvalue is an lvalue that does not have array type,
does not have an incomplete type, does not have a
const-qualiﬁed type, and if it is a structure or union, does
not have any member (including, recursively, any member or
element of all contained aggregates or unions) with a
|name must be a variable
|e must be an lvalue
|e must be an lvalue
These are not lvalues - array names, functions, enumerated
constants, assignment expressions, casts, and function calls.
The following operators require an lvalue operand.
- A function designator
is a value of function type. It is neither an object nor
|operand must be an lvalue or
a function name
prefix and postfix forms)
|operand must be an lvalue
-= *= /= %=
<<= >>= &= ^= |=
|left operand must be an
The type qualifiers
restrict affect the
modifiability of objects when accessed through lvalues.
- There are seven possible qualified versions of each
- The order in which the qualifiers appear is not important.
- C11 added the type qualifier
- An lvalue expression of a
cannot be used to modify an object.
- See the handout for the distinction between "constant pointer"
and "pointer to constant data".
- The compiler is allowed to allocate an object of
storage, unless it is also volatile.
volatile-qualified object can have its value
altered in some way not under the control of the compiler.
- That is, the most-recent-store to a volatile object need not
be explicit in the program.
- The compiler cannot perform certain optimizations, such as
keeping the variable only in a register, or assuming an
expression has no hidden side effects.
- From the C11 Standard: "Accessing a volatile object, modifying
an object, modifying a ﬁle, or calling a function that does any
of those operations are all side effects, which are
changes in the state of the execution environment. Evaluation
of an expression in general includes both value computations and
initiation of side effects. Value computation for an
lvalue expression includes determining the identity of the
- The remaining question is, when are the side effects
finalized? This leads to the definition of sequence
points, as follows:
- In the C99 Standard:
- "Accessing a volatile object, modifying an object, modifying
a file, or calling a function that does any of those
operations are all side effects, which are changes in
the state of the execution environment. Evaluation of an
expression may produce side effects. At certain
specified points in the execution sequence called sequence
points, all side effects of previous evaluations shall
be complete and no side effects of subsequent evaluations
shall have taken place. (A summary of the sequence
points is given in annex C.)"
- In the C11 Standard:
- "Sequenced before is an asymmetric, transitive,
pair-wise relation between evaluations executed by a single
thread, which induces a partial order among those
evaluations. Given any two evaluations A and B, if A is
sequenced before B, then the execution of A shall precede the
execution of B. (Conversely, if A is sequenced before B,
then B is sequenced after A.) If A is not
sequenced before or after B, then A and B are unsequenced.
Evaluations A and B are indeterminately sequenced when
A is sequenced either before or after B, but it is unspecified
which. The presence of a sequence point between
the evaluation of expressions A and B implies that every value
computation and side effect associated with A is sequenced
before every value computation and side effect associated with
B. (A summary of the sequence points is given in annex
Example (CP:AMA, p. 479)
restrict-qualified pointer is, for the moment,
the only way to refer to the object to which it points.
- The compiler may then allow optimizations that depend on "no
- For example, copy data from
assuming there is no overlap in the two memory areas (
or allowing overlap (
void *memcpy(void * restrict s1, const void * restrict s2,
void *memmove(void * s1, const void * s2, size_t n);
restrict is only a hint to the compiler, which is
free to ignore it.
restrict should be taken seriously by the
programmer, as it clarifies your thinking about function design
- For the formal definition of
see the C Standard. Otherwise, see CP:AMA Sec. 17.8.
extern const volatile int real_time_clock;
- The program can't change the value of
const) but something else could (it's
- A constant is not the same as a const-qualified object.
For example, in
const int a = 2;
2 is a constant,
and a is an lvalue
referring to a const-qualified
Last revised, 15 Feb. 2013