Ordinary int
is mutable. An entity that is (not merely claimed to be at some point, but "really is") const
is not-mutable-in-theory and if the hardware and software cooperate, often not-mutable-in-fact as well.
Defining a variable using the const
qualifier makes it "really" const:
const int c3 = 3;
void f(void) {
const int c4 = 4;
...
}
With "tricky" code (casting away the const-ness) you can convince the system to write, or attempt to write, new values into c3
and/or c4
:
void f(void) {
const int c4 = 4;
int *p;
p = (int *)&c3;
*p = 99;
printf("c3 is now %d\n", c3);
}
If you call f()
you may, on some systems, find that c3 changes and becomes 99. On other systems you may get a "segmentation fault" or other run-time error.
Change the references to use c4
and the same things can happen—although in practice, few if any systems produce a run-time error. However, you may observe something else entirely: instead of printing c4 is now 99
you may get c4 is now 4
.
This last can happen because the compiler is allowed to assume that, having made c4
a const int
with value 4, you, the programmer, never changed it. That *p = 99
must not have changed it (even if it did), so the call to printf
can be replaced with a different call that just prints 4.
The same is generally true of references to c3
: the compiler can assume that since you promised never to change it, you never actually did change it. This can produce surprising results, such as: p == &c3
being true, c3
being 3, and *p
being 99. But a run-time error is pretty likely, because most modern compilers and OSes cooperate to stick c3
into a read-only region.
When string literals produce arrays (which is most of the time), C has a quirk. These arrays are not const
-qualified, but the characters making up the array are read-only anyway (at least in principle, as with const int c3 = 3;
). Like c3
, most modern systems manage to make them "really read-only".
(String literals do not produce arrays when they are used as initializers for objects of type array of char
. Compare:
char *ronly = "this string is read only";
char rwarray[] = "this string is read/write";
Here ronly
is a pointer, not an array, so the string literal produces an array and ronly
points to the first character of that array. The underlying array is read-only, even though its type is char [25]
. But rwarray
is an array, not a pointer, so the string literal fills it in—and sets its size to 26—and it is mutable. You would have to write const char roarray[] = ...
to make it immutable. [Some like to spell the type char const []
, with the const coming after the data-type. These mean the same thing.])