The *
indirection operator is a unary operator, meaning its operand is to the right of the operator, as in *p
.
C declarations are broken into two major sections - a sequence of declaration specifiers (type specifiers, storage class specifiers, type qualifiers, etc.) followed by a comma-separated list of declarators. A declarator introduces the name of the thing being declared, along with information about that thing’s array-ness, pointer-ness, and function-ness. In the declaration statement
int a[10], *p, f(void);
the declaration specifier is int
and the declarators are a[10]
, *p
, and f(void)
. Note that the *
is bound to the declarator, not the type specifier. Because it’s a unary operator and token on its own, you don’t need whitespace to separate the type specifier from the identifier - all of
int *p;
int* p;
int*p;
int * p;
are equally valid, and all are interpreted as int (*p);
- the operand of *
is always p
, not int
or any other type specifier1.
The type of a
is "10-element array of int
", which is fully specified by the combination of the int
type specifier and by the [10]
in the declarator. Similarly the type of p
is "pointer to int
", which again is fully specified by the combination of the type specifier and the *
operator in the declarator. And the type of f
is "function returning int
" by the same reasoning.
This is key - there is no type specifier for pointer, array, or function types - they can only be specified by a combination of one or more declaration specifiers and a declarator.
So how do we specify pointer types (or array or function types) in a cast? Basically, we write a declaration composed of declaration specifiers and a declarator, but with no identifier. If we want to cast something as a pointer to int
, we write it as a regular pointer declaration with an unnamed variable - (int *)
.
- This is why I’m not fond of the C++ convention of writing pointer declarations as
T* p;
; it doesn’t follow the syntax, and it’s inconsistent - a declaration like int* a[N];
is schizophrenic. It also introduces confusion when you write something like T* p, q;
because it looks like you intend to declare both p
and q
as pointers, but only p
is.