Embedded Basics – Peculiarities of the keyword const

The keyword const in C can at best be a misleading type qualifier. One would think that const would specify that a particular symbol is a constant but unfortunately that is not the case. The best definition a C developer can use for const is that it provides “read-only” access to the memory location that the symbol represents. Take for example the following declaration:

const int x = 14;

The declaration is stating that x is a read-only symbol with the value of 14. Attempts to modify x using the symbol x will all result in compiler warnings as one might expect of a constant. The keyword const does not protect the memory location that x occupies from being manipulated in an indirect manner. Take for example the following code:

int * y = &x;

The statement above is creating a pointer to the memory location that the read-only x symbol occupies. One would think that if the pointer attempted to change the value that it would not be allowed, unfortunately this is not the case. By dereferencing y and providing a new value such as 16, the memory location can be indirectly modified and the value of x is now 16.

*y = 16; /* Completely valid! */

A developer that is paying close attention would realize that y is a pointer to a const, and the declaration could be changed to

const int * y = &x;

Attempts to dereference the pointer and change the value would now be caught by the compiler. All now seems right with the world, except for when another developer comes along, decides they want to change the value through the pointer and now cast away the const, forcing the value to be changed as follows:

*(int *)y = 16;

Obviously this type of behavior would be highly frowned upon but it is important to realize that const behaves in this way. Another interesting point related to declaring the pointer y is that while the pointer is pointing to a read-only integer, the pointer itself is not read-only! Code such as the following would be perfectly legitimate:

y++;

y–;

y = y+0x1000;

What is a developer to do to make sure that the pointer can’t be changed to point to anything but x? A confusing declaration such as the following can be used:

const int * const y = &x;

The above declaration is defining the symbol y to be a read-only pointer to an integer that is read-only. Confused yet?

One of the advantages of using const in an embedded system is that in many cases declaring a symbol as const will force that symbol to be stored in ROM. When the symbol is stored in ROM, the indirect methods of trying to change the value of the symbol will not work. The danger is that the behavior is not specified in the C standard! A developer has to take care to understand what the compiler is doing and where it is storing the read-only values.

Despite the peculiarities of const, it is still important to use it where appropriate and to protect symbols that should be read-only. One area of recommended heavy use is to protect parameters being passed to a function from being written to.