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?
Two real world examples
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
constmodifier is trivial: it modifies what precedes it, unlessnothing precedes it. So:
, 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 toremember that when no type precedes the
const, you have to logicallymove it behind the first type. So:
is in fact:
, 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:
is:
a pointer to a const pointer to a char.