There's a C function declaration signal
from c-faq website example 3:
void (*signal(int, void (*fp)(int)))(int);
I wonder how can there be two identifiers signal
, fp
and it still passes compilation (I added this line randomly in my existing code and it compiles successfully)?
No, a C function declaration/prototype cannot have any more than one identifier. Refer to the reference page and example code for signal
on cplusplus.com here: http://www.cplusplus.com/reference/csignal/signal/.
In this declaration:
void (*signal(int sig, void (*func)(int)))(int);
we are declaring a function called signal
which returns a pointer to a function which returns void
and accepts an int
--ie: a pointer to a function like this:
void func(int);
The inputs to the signal
function are 1st, an int
, and 2nd, a pointer to a function which returns a void
and accepts an int
--again, a pointer to a function like func
above. Now, in C, when declaring a function which returns a pointer to a function and accepts a pointer to a function, it gets all goobly-ga-gook-looking (garbled and confusing looking), which is why we all have confusion initially (and again and again frequently) looking at function declarations like signal
. A couple much much much clearer ways to define a function like signal
in C, to make this all crystal-clear, are like this, instead, both of which are identical to the goobly-gook-looking one:
// 1. typedef a function--call it `func_t` for "func type"
typedef void func_t(int);
// 2. Use the typedef above to define `signal`
func_t* signal(int sig, func_t* fp); // Ah, now this makes sense!
OR
// 1. typedef a *pointer to* a function--call it `func_p` for "pointer to a func type"
typedef void (*func_p)(int);
// 2. Use the typedef above to define `signal`
func_p signal(int sig, func_p fp); // Ah, now this makes sense too!
And remember, what you call each input parameter type in a function declaration is irrelevant in C and doesn't even have to match between a header and source file.
Ex:
my_module.h:
// Any of these 3 prototypes are equivalent, valid, and identical
// (although using sensible names which match between the header &
// source files is most clear and helpful to the reader!):
func_p signal(int sig, func_p fp);
func_p signal(int signal, func_p whatsupdude);
func_p signal(int, func_p);
my_module.c:
func_p signal(int sig, func_p fp)
{
// define the function here
}
Now, how did I initially figure all this out?
Ans: I looked at the example code from cplusplus.com. It helped a TON to make this all clear, as you can see how the return value from signal
is assigned to prev_handler
, which is a pointer to a function, and you can see how my_handler
, which is defined as a function, is passed in as the 2nd parameter to signal
! For kicks, I should probably also mention that these 2 lines are identical, and both are perfectly valid:
prev_handler = signal (SIGINT, my_handler);
prev_handler = signal (SIGINT, &my_handler);
This is because if you pass in a function as a parameter the compiler knows to just take its address anyway.
/* signal example */
#include <stdio.h> /* printf */
#include <signal.h> /* signal, raise, sig_atomic_t */
sig_atomic_t signaled = 0;
void my_handler (int param)
{
signaled = 1;
}
int main ()
{
void (*prev_handler)(int);
prev_handler = signal (SIGINT, my_handler);
/* ... */
raise(SIGINT);
/* ... */
printf ("signaled is %d.\n",signaled);
return 0;
}