I was studying C99 - Function pointer part and my textbook offered a way to use 'typedef' for simplifying the code below :
int (*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
↓
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
I've known that 'typedef' can be used only like this : eg.
typedef unsigned short int US;
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};
I can't understand why the second sentence could be like that.
CodePudding user response:
The typedef
keyword behaves grammatically like storage modifiers (i.e. auto
, register
, static
etc) except the initialization part. My guess the reason for that is that the early versions of C compilers shared code between variable declaration and type alias declarations.
Therefore the type alias declaration and variable declaration look more or less the same:
static int (*A[4])(int,int); // staic variable
typedef int (*B[4])(int,int); // type alias
int (*C[4])(int,int); // local variable
I guess the question is why one cannot do:
int (*[4])(int,int) C;
I have no good answer to that, C grammar is simply defined this this way. I can guess that without the anchor the compiler cannot correctly parse the type.
So why one can't do:
(int (*[4])(int,int)) C;
Answer:
It would solve the problem with missing anchor. However, it cannot be used because it will conflict with cast operator (type) expr
. Note that symbol C
may be defined on out scope resulting in ambiguity.
int C;
{
// cast `C` to `int*` or maybe declare a pointer to `int`
(int*)C;
}
However, there is a workaround with typeof
extension (a feature in upcoming C23).
typeof(int (*[4])(int,int)) C;
This is more or less the same how the compiler expands the following declaration:
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
to
typeof(int(*)(int,int)) p[4] = { ... }
Moreover, using this trick allows a neat and readable declaration of complex types.
typeof(int(int,int))* p[4] = { .... }
It is easy to see that p
is a 4-element array of pointers to int(int,int)
function.
CodePudding user response:
int
is not "altered" by a typedef
. typedef unsigned short int US;
is not "altering" unsigned short int
, it is defining the identifier US
to denote the same type as unsigned short int
. Likewise, typedef int (*OP_TYPE)(int,int)
is defining the identifier OP_TYPE
to denote the same type as int (*)(int, int)
(a pointer to a function returning int
with parameter type list int, int
).
Syntactically, typedef
is like a storage class specifier but it defines a "typedef name" instead of declaring a variable. Compare typedef int (*OP_TYPE)(int, int);
to static int (*op)(int, int);
. OP_TYPE
is a typedef name and op
is a variable. OP_TYPE
and op
both have the same type int (*)(int, int)
. OP_TYPE
can be used as a type in subsequent declarations, so that static OP_TYPE op;
is equivalent to static int (*op)(int, int);
CodePudding user response:
Welcome to stackoverflow @moveityourself01!
OP_TYPE is a function pointer type. Here is an example:
// This is a function
// It has a single parameter and returns
// an int
int some_func(int a) {
return(a 1);
}
int main(void) {
// regular usage of the function
printf("some_func(1) = %d\n", some_func(1));
// fun_ptr is a function pointer
// that points to the function some_func
int (*fun_ptr)(int) = &some_func;
printf("via fun_ptr->some_func(2) = %d\n", fun_ptr(2));
// create the typedef
typedef int (*funptr_type)(int);
// usage of typedef
funptr_type another_func_ptr = &some_func;
// usage of function pointer via typedef
printf("via typedef some_func(3) = %d\n", another_func_ptr(3));
return(0);
}
Usage
some_func(1) = 2
via fun_ptr->some_func(2) = 3
via typedef some_func(3) = 4