C Declarations are Expressions
There have been lots of attempts at clearing up how to read C declarations. Because, let's face it, they're unreadable. Any language where you can type
char (*(*x())[])()
And have it mean something sensible is crazy. Why does *
designate a
pointer? &
takes the address, not *
. Why is [] backwards? The "outermost"
levels of the array are the innermost in the declaration. And the parentheses
are all over the place, obscuring what is actually being declared.
This is so confusing that people have written tools like cdecl to to help you decipher them and convert them to English. People have invented rules such as the spiral rule. And because the C declaration syntax is confusing, these tools are in fact helpful.
However, you may have also heard that in C, "declaration follows usage". And what this implies is that the right hand side of a declaration isn't just a random bunch of gibberish. It's an expression that you apply to the name in order to get back the type on the left hand side.
Starting off simply, that means the declaration:
int x
means that to get back a value of type int
, you write x
. If the
declaration was instead:
int *x
that would mean that to get a value of type int
, you write the expression
*x
. All of these expressions are just C expressions, with all of the usual
operator precedence rules. Keeping the precedence rules in mind, and knowing
that postfix binds more tightly than prefix, we know that:
int *x[10]
is parenthesized as:
int *(x[10]).
In other words, it is an array of 10 pointers to int. The array subscript
binds more tightly than the pointer, meaning that whatever x[idx]
evaluates
to must be something that can be dereferenced.
Making sense of the initial example is left as an exercise.