Was it not wrong, int
would be altered as (*OP_TYPE)(int,int)
, and Isn't it right the second sentence become (*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
The declaration
typedef int (*OP_TYPE)(int, int);
does not change the meaning of int
- it changes the meaning of OP_TYPE
.
First, some background:
Declarations in C are broken into two main sections: a sequence of declaration specifiers, followed by a comma-separated list of declarators.
The declarator introduces the name of the thing being declared, along with information about that thing's array-ness, function-ness, and pointer-ness. In a typedef, that name becomes an alias for the type.
The structure of the declarator is meant to mirror the structure of an expression in the code. For example, suppose you have an array arr
of pointers to int
and you want to access the integer object pointed to by the i
’th element; you’d index into the array and dereference the result, like so:
printf( "%d\n", *arr[i] ); // *arr[i] is parsed as *(arr[i])
The type of the expression *arr[i]
is int
; that's why we write its declaration as
int *arr[N];
instead of
int *[N] arr;
In the expression, the operand of the postfix []
subscript operator is arr
, and the operand of the unary *
dereference operator is the expression arr[i]
. Those operators follow the same rules of precedence in a declaration, hence the structure of the declaration above.
The declaration reads as
arr -- arr
arr[N] -- is an array of
*arr[N] -- pointer to
int *arr[N]; -- int
Thus, object named arr
has type "array of pointer to int
";
Similarly, if you have an array of function pointers and you want to call one of those functions, you’d index into the array, dereference the result, and then call the resulting function with whatever arguments:
x = (*p[i])(a, b);
Again, the type of the expression (*p[i])(a, b)
is int
, so it follows that the declaration of p
is written
int (*p[4])(int, int);
and not
int (*[4])(int, int) p;
Again, the declaration reads as
p -- p
p[4] -- is a 4-element array of
*p[4] -- pointer to
(*p[4])( ) -- function taking
(*p[4])( , ) -- unnamed parameter
(*p[4])(int, ) -- is an int
(*p[4])(int, ) -- unnamed parameter
(*p[4])(int, int) -- is an int
int (*p[4])(int, int); -- returning int
so the object named p
has the type "array pointer to function taking two int
parameters and returning int
".
Clear so far?
So, how does typedef
affect this?
Let's start with a declaration without the typedef
:
int (*OP_TYPE)(int, int);
This declares OP_TYPE
as an object of type "pointer to function taking two int
parameters and returning int
". If we add the typedef
keyword:
typedef int (*OP_TYPE)(int, int);
it changes the meaning of the declaration such that OP_TYPE
is an alias for the type "pointer to function taking two int
parameters and returning int
". It doesn't change the structure of the declaration at all, only the meaning. Thus, you can write
OP_TYPE fp;
and it will mean exactly the same thing as
int (*fp)(int, int);
Some other examples may help drive the concept home; going back to the earlier examples, if
int *ap[N];
declares ap
as an object of type "4-element array of pointer to int
", then
typedef int *ap[N];
declares ap
as an alias for the type "4-element array of pointer to int
", such that
ap foo;
is equivalent to
int *foo[N];
If
int (*blah)[N];
declares blah
as an object of type "pointer to N-element array of int
", then the declaration
typedef int (*blah)[N];
declares blah
as an alias for the type "pointer to N-element array of int
".
In the example you provide,
unsigned short int US;
declares US
as object of type unsigned short int
; thus,
typedef unsigned short int US;
declares US
as an alias for the type unsigned short int
.
Declarations (and thus typedefs
) can get arbitrarily complex:
int *(*(*foo())[N])(double);
foo
is a pointer to a function that returns a pointer to an array of pointers to functions taking a double
parameter and returning a pointer to int
. Adding a typedef
:
typedef int *(*(*foo())[N])(double);
changes foo
to be an alias for the type "function returning a pointer to an array of pointers to functions taking a double
parameter and returning a pointer to int
; again,
foo bar;
is equivalent to writing
int *(*(*bar())[N])(double);