3

I was studying signal handling in unix and came across this

void (*signal(int sig, void (*func)(int)))(int);

I dont understand this prototype and how this returns a pointer to a function.

I also read this answer: How do function pointers in C work? but it's not clear to me.

It's supposed to return a function pointer but I dont understand where it specifies the return type as another function pointer.
The way I see it is that, if I use (*foo(int n)) in a function definition the return type of this function foo(int n) becomes a function pointer.Is this correct?
Is there a simpler example for this?

Community
  • 1
  • 1
rs911
  • 33
  • 4
  • 2
    Also: [the cdecl explanation](http://cdecl.ridiculousfish.com/?q=void+%28*signal%28int%2C+void+%28*%29%28int%29%29%29%28int%29) – millimoose Aug 12 '13 at 00:20
  • Also, the return type becomes a function pointer by adding a parameter list after the function signature. (Which already contains an unrelated parameter list.) Compare [`void (*foo(int))`](http://cdecl.ridiculousfish.com/?q=void+%28%2Afoo%28int%29%29) (which is the same as `void *foo(int)` but not `void (*foo)(int)`) and [`void (*foo(int))(long)`](http://cdecl.ridiculousfish.com/?q=void+%28*foo%28int%29%29%28long%29). To put it another way: the return type of a function is the stuff *outside* the signature, not just to the left of it. – millimoose Aug 12 '13 at 01:07

3 Answers3

3

So, let's look at how a function pointer is declared.

return-type (*function-name)(parameter-list);

In the declaration you posted, there are two function-pointer types in play. The first is a parameter that's passed into a function that matches the signal prototype:

void (*signal(int sig, void (*func)(int)))(int);
//                     ^^^^^^^^^^^^^^^^^

Let's rename that function pointer type to handler and give it its own declaration.

typedef void (*handler)(int);
void (*signal(int sig, handler func))(int);

Now we can break down the rest of the declaration. The "inside" part is the actual function declaration:

...signal(int sig, handler func)...

And the "outside" describes the function pointer it returns:

void (...)(int);

This is also the same function-pointer type as our handler type, so with that typedef in place, we could redeclare the signal function like this:

handler signal(int sig, handler func);

(Much prettier.)

Adam Maras
  • 26,269
  • 6
  • 65
  • 91
1
void (*signal(stuff))(int)

declares signal as returning a pointer to a function that takes an int as an argument and returns void. The stuff gives the arguments to signal, which in this case are

(int sig, void (*func)(int))

That is, the first argument to the function signal is an int, and the second argument is a function pointer taking an int as an argument and returning void.

Edit: Thus, if you made some call -- for example,

void foo (int x) {
    return;
}
void *bar = (*signal)(0, &foo);

then bar will be a pointer to a function taking an int and returning nothing, and as such can be called as follows:

(*bar)(0);
qaphla
  • 4,707
  • 3
  • 20
  • 31
1

We can use typedef to simplify the function pointer definition, which can help you to understand the long and complicated definition.

#include <stdio.h>
typedef void (*func)(int);
typedef void (*rtype)(int);

void myfunc(int a)
{
    printf("A is %d\n", a);
}

// thus signal can be defined as this
// exactly the same as in your question
rtype signal(int a, func handler)
{
    return myfunc;
}

int main()
{
    signal(0, 0)(12);
    return 0;
}

the above code should output: A is 12;

Hope helps!

Hanfeng
  • 645
  • 5
  • 11