For reading complex pointer declarations there is the right-left rule.
But this rule does not mention how to read const
modifiers.
For example in a simple pointer declaration, const
can be applied in several ways:
char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory
Now what about the use of const
with a pointer of pointer declaration?
char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;
And what is an easy rule to read those declarations? Which declarations make sense?
Is the Clockwise/Spiral Rule applicable?
The method ASTUnit::LoadFromCommandLine
uses const char **
to supply command line arguments (in the llvm clang source).
The argument vector parameter of getopt()
is declared like this:
int getopt(int argc, char * const argv[], const char *optstring);
Where char * const argv[]
is equivalent to char * const * argv
in that context.
Since both functions use the same concept (a vector of pointers to strings to supply the arguments) and the declarations differ - the obvious questions are: Why do they differ? Makes one more sense than the other?
The intend should be: The const
modifier should specify that the function does not manipulate strings of this vector and does not change the structure of the vector.
The const
modifier is trivial: it modifies what precedes it, unless
nothing precedes it. So:
char const* buffer; // const modifies char
char* const buffer; // const modifies *
, etc. Generally, It's best to avoid the forms where nothing precedes
the const
, but in practice, you're going to see them, so you have to
remember that when no type precedes the const
, you have to logically
move it behind the first type. So:
const char** buffer;
is in fact:
char const** buffer;
, i.e. pointer to pointer to const char.
Finally, in a function declaration, a []
after reads as a *
before.
(Again, it's probably better to avoid this misleading notation, but
you're going to see it, so you have to deal with it.) So:
char * const argv[], // As function argument
is:
char *const * argv,
a pointer to a const pointer to a char.