the origin c declaration is
void (*signal(int signo, void (*func)(int)))(int);
I could understand this statement declare a function call signal that takes an int and an pointer to a function as parameters and returns a pointer to a function. But the use of the typedef as follows is hard to understand:
typedef void Sigfunc(int);
Sigfunc *signal(int signo, Sigfunc *func);
If I replace the "Sigfunc" with "void (int)", I couldn't transform the second declaration to the first. How to interpret the typedef in a right way.
What'more , can I write the following code to get the equivalent declaration
typedef void (*p_Sigfunc)(int);
p_Sigfunc signal(int signo, p_Sigfunc func);
CodePudding user response:
Case 1
In the statement:
void (*signal(int signo, void (*func)(int)))(int);
The above is a declaration for a function named signal that has the following properties:
signaltakes two parameters. The first parameter ofsignalis of typeintand is namedsigno. The second parameter ofsignalis of typevoid(*)(int)and is namedfunc. That is,funcis a pointer to a function with one parameter of typeintand return type ofvoid.signalhas the return typevoid (*)(int). That is the return type ofsignalis a pointer to a function that takes one parameter of typeintand has return type ofvoid.
To make this more readable we can use the placeholder type auto and decltype in C 11(as this question was originally tagged C also) as shown below:
//more readable
auto signal(int signo, void (*func)(int)) -> void(*)(int);
Case 2
Now lets look at the second case:
typedef void Sigfunc(int); //Sigfunc is a typedef for the function type void (int)
Sigfunc *signal(int signo, Sigfunc *func);
SigFunc is a typedef for the function type void (int). Thus Sigfunc* is nothing but void (*)(int). And since in this case the return type is specified as Sigfunc*, the return type is the same as void (*)(int). Note that specifying the * is important here.
Case 3
Now lets look at case 3:
typedef void (*p_Sigfunc)(int); //p_Sigfunc is a typedef for void (*)(int)
p_Sigfunc signal(int signo, p_Sigfunc func);
//--------^------------------------------------>no need for explicitly writing "*" here
Here p_Sigfunc is a typedef for void (*)(int). Note in this case we don't need to the * because we already have void (*)(int) instead of void (int).
All of these function declarations are equivalent.
CodePudding user response:
Breaking it down:
typedef void Sigfunc(int);
Sigfunc *signal(int signo, Sigfunc *func);
So two things - the func parameter is a pointer to Sigfunc and signal returns a pointer to Sigfunc.
Since Sigfunc is an alias for "function taking an int parameter and returning void", then Sigfunc * declares a pointer to a function taking an int parameter an returning void. IOW:
Sigfunc f == void f(int);
Sigfunc *p == void (*p)(int);
Thus,
Sigfunc *signal( int signo, Sigfunc *func ) ==
Sigfunc *signal( int signo, void (*func)(int)) ==
void (*signal( int signo, void (*func)(int) ))(int)
And yes, you can do
typedef void (*p_Sigfunc)(int);
p_Sigfunc signal( int signo, p_Sigfunc func );
But...
I am not a fan of hiding pointers (including function pointers) behind typedefs in general. Pointer semantics are special, and unless you are willing to build an API that completely isolates pointer-ness (such that the user of the type doesn't have to be aware of it at all), don't hide them behind a typedef.
CodePudding user response:
Try this approach, to understand this.
typedef void Sigfunc(int);
This type says: a function that takes an int and returns void.
typedef Sigfunc *Sigfunc2;
This type says: a pointer to a Sigfunc. And since Sigfunc is a function that takes an int and returns void then: this is a pointer to a function that takes an int and returns void; which is, again:
typedef void (*Sigfunc2)(int);
This type says the same thing: a pointer to a function that takes an int and returns void.
