The const
, volatile
and restrict
(C99 onwards) keywords are considered type qualifiers. They are an integral part of type signatures and describe additional semantics about a type.
If they appear at the topmost level of a declaration, they affect the declared identifier:
const int a = 5; // prevents modifications of "a"
int *const p = &x; // prevents modifications of "p", but not "*p"
int **const q = &y; // prevents modifications of "q", but not "*q" and "**q"
If they appear in pointer subtypes (before an asterisk), they affect the pointed-to value at the particular level of dereferencing:
const int *p = &x; // prevents modifications of "*p", but not "p"
const int **q = &y; // prevents modifications of "**q", but not "*q" and "q"
const int *const *r = &z; // prevents modifications of "**r" and "*r", but not "r"
const int *const *const s = &a; // prevents modifications of "**s", "*s" and "s"
The Wikipedia excerpt discusses two different conventions for declaring pointers:
int *p; // more common in C programming
int* p; // more common in C++ programming
I would say that the "true" convention is the first one because it works according to the syntax of the language (declarations mirror use). The asterisk in that declaration is in fact the same dereferencing operator that you would use on the pointer in normal expressions. Thus the int
type is returned after applying *
(indirection) on p
(the pointer itself).
Also note that the ordering of type qualifiers with respect to type specifiers and other type qualifiers does not matter, so these declarations are equivalent:
const int a; // preferred
int const a; // same, not preferred
const volatile int b; // preferred
volatile const int b; // same, not preferred
volatile int const b; // same, not preferred
const int *p; // preferred
int const *p; // same, not preferred