|Access||Adobe photoshop||Algoritmi||Autocad||Baze de date||C||C sharp|
|Calculatoare||Corel draw||Dot net||Excel||Fox pro||Frontpage||Hardware|
|Php||Power point||Retele calculatoare||Sql||Tutorials||Webdesign||Windows|
|Asp||Autocad||C||Dot net||Excel||Fox pro||Html||Java|
These are new in Standard C, although the idea of
const has been borrowed from C++. Let us
get one thing straight: the concepts of
volatile are completely
independent. A common misconception is to imagine that somehow
const is the opposite of
volatile and vice versa. They are
unrelated and you should remember the fact.
are the simpler, we'll look at them first, but only after we have seen where
both of these type qualifiers may be used. The complete list of relevant
In that list,
volatile are type qualifiers, the rest
are type specifiers. Various combinations of type specifiers are
A few points should be noted. All declarations to do with an
int will be
signed anyway, so signed is redundant in that context. If any other type
specifier or qualifier is present, then the int part may be dropped, as that is
volatile can be applied to any
declaration, including those of structures, unions, enumerated types or
typedef names. Applying them to a
declaration is called qualifying the declaration—that's why const
and volatile are called type qualifiers, rather than type specifiers. Here are
a few representative examples:
Don't be put off; some of them are deliberately complicated: what they mean will be explained later. Remember that they could also be further complicated by introducing storage class specifications as well! In fact, the truly spectacularextern const volatile unsigned long int rt_clk;
is a strong possibility in some real-time operating system kernels.
Let's look at what is meant when
is used. It's really quite simple:
means that something is not modifiable, so a data object that is declared with
const as a part of its type
specification must not be assigned to in any way during the run of a program.
It is very likely that the definition of the object will contain an initializer
(otherwise, since you can't assign to it, how would it ever get a value?), but
this is not always the case. For example, if you were accessing a hardware port
at a fixed memory address and promised only to read from it, then it would be
declared to be
const but not
Taking the address of a data object of a type which isn't
const and putting it into a pointer to
of the same type is both safe and explicitly permitted; you will be able to use
the pointer to inspect the object, but not modify it. Putting the address of a
const type into a pointer to the unqualified type is much more dangerous and
consequently prohibited (although you can get around this by using a cast).
Here is an example:
As the example shows, it is possible to take the address of a constant object, generate a pointer to a non-constant, then use the new pointer. This is an error in your program and results in undefined behaviour.
The main intention of introducing const objects was to allow them to be put
into read-only store, and to permit compilers to do extra consistency checking
in a program. Unless you defeat the intent by doing naughty things with
pointers, a compiler is able to check that
objects are not modified explicitly by the user.
An interesting extra feature pops up now. What does this mean?char c;
It's simple really;
a pointer to a
is exactly what it would be if the
const weren't there. The
const means that
cp is not to be modified, although
whatever it points to can be—the pointer is constant, not the thing that it
points to. The other way round is
which means that now cp is an ordinary, modifiable pointer, but the thing that it points to must not be modified. So, depending on what you choose to do, both the pointer and the thing it points to may be modifiable or not; just choose the appropriate declaration.
After const, we treat
The reason for having this type qualifier is mainly to do with the problems
that are encountered in real-time or embedded systems programming using C.
Imagine that you are writing code that controls a hardware device by placing
appropriate values in hardware registers at known absolute addresses.
Let's imagine that the device has two registers, each 16 bits long, at ascending memory addresses; the first one is the control and status register (csr) and the second is a data port. The traditional way of accessing such a device is like this:/* Standard C example but without const or volatile */
The technique of using a structure declaration to describe the device register layout and names is very common practice. Notice that there aren't actually any objects of that type defined, so the declaration simply indicates the structure without using up any store.
To access the device registers, an appropriately cast constant is used as if it were pointing to such a structure, but of course it points to memory addresses instead.
However, a major problem with previous C compilers would be in the while
loop which tests the status register and waits for the
READY bit to come on. Any self-respecting optimizing compiler
would notice that the loop tests the same memory address over and over again.
It would almost certainly arrange to reference memory once only, and copy the
value into a hardware register, thus speeding up the loop. This is, of course,
exactly what we don't want; this is one of the few places where we must look at
the place where the pointer points, every time around the loop.
Because of this problem, most C compilers have been unable to make that sort
of optimization in the past. To remove the problem (and other similar ones to
do with when to write to where a pointer points), the keyword
volatile was introduced. It tells the
compiler that the object is subject to sudden change for reasons which cannot
be predicted from a study of the program itself, and forces every reference to
such an object to be a genuine reference.
Here is how you would rewrite the example, making use of
volatile to get what you want.
The rules about mixing
and regular types resemble those for
A pointer to a
object can be assigned the address of a regular object with safety, but it is
dangerous (and needs a cast) to take the address of a
volatile object and put it into a
pointer to a regular object. Using such a derived pointer
results in undefined behaviour.
If an array, union or structure is declared with
volatile attributes, then all of the members take on that
attribute too. This makes sense when you think about it—how could a member of a
const structure be
That means that an alternative rewrite of the last example would be
possible. Instead of declaring the device registers to be
volatile in the structure, the pointer
could have been declared to point to a
structure instead, like this:
dvp points to a
volatile object, it not permitted to
optimize references through the pointer. Our feeling is that, although this
would work, it is bad style. The
declaration belongs in the structure: it is the device registers which are
volatile and that is where the
information should be kept; it reinforces the fact for a human reader.
So, for any object likely to be subject to modification either by hardware or asynchronous interrupt service routines, the volatile type qualifier is important.
Now, just when you thought that you understood all that, here comes the final twist. A declaration like this:volatile struct devregsv_decl;
declares the type
struct devregs and also a
volatile-qualified object of that type, called
v_decl. A later declaration like this
which is not qualified with
The qualification is not part of the type of
struct devregs but applies only to the
at it this way round, which perhaps makes the situation more
clear (the two declarations are the same in their effect):
If you do want to get a shorthand way of attaching a qualifier to another
type, you can use
Those of you who are familiar with techniques that involve hardware
interrupts and other ‘real time’ aspects of programming will recognise the need
volatile types. Related
to this area is the need to ensure that accesses to data objects are ‘atomic’,
or uninterruptable. To discuss this is any depth would take us beyond the scope
of this book, but we can at least outline some of the issues.
Be careful not to assume that any operations written in C are uninterruptable. For example,extern const volatile unsigned long realtimeclock;
could be a counter which is updated by a clock
interrupt routine. It is essential to make it
volatile because of the asynchronous updates to it, and
it is marked
it should not be changed by anything other than the interrupt routine. If the
program accesses it like this:
there may be a problem. What if, to copy one
long into another, it takes several
machine instructions to copy the two words making up
time_of_day? It is possible that an
interrupt will occur in the middle of the assignment and that in the worst
case, when the low-order word of
0xffff and the high-order
then the low-order word of
interrupt arrives and increments the low-order word of
0x0 and then the high-order word to
0x1, then returns. The rest of the
assignment then completes, with
ending up containing
containing the correct value,
This whole class of problem is what is known as a critical region, and is well understood by those who regularly work in asynchronous environments. It should be understood that Standard C takes no special precautions to avoid these problems, and that the usual techniques should be employed.
declares a type called
which is guaranteed to be modifiable safely in the presence of asynchronous
events. This means only that it can be modified by assigning a value to it;
incrementing or decrementing it, or anything else which produces a new value
depending on its previous value, is not safe.
Politica de confidentialitate|
Adauga cod HTML in site