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

I can't follow this kind of explanation of syntax too clearly. I know it's simple but I'd rather watch a quick video or read a book about the style/software engineering concept of this. Basically how may I explain this as a coder?

Thomas Padron-McCarthy
  • 27,232
  • 8
  • 51
  • 75
Krisgoku2
  • 29
  • 5
  • Are you asking "What is `signal` in this declaration, and why?" [Perhaps cdecl.org will help](http://cdecl.org/?q=void+%28*signal%28int%2C+void+%28*%29%28int%29%29%29%28int%29%3B). It is also one of the rare times a pointer type (in this case a function pointer) hidden in a typedef would make the code *easier* to understand and use: [it is synonymous to this](http://pastebin.com/sTPU0t2j). – WhozCraig Mar 25 '17 at 08:57
  • I find this link extremely helpful: http://c-faq.com/decl/spiral.anderson.html – vsoftco Mar 25 '17 at 09:15
  • 3
    "I know it's simple" - judging by the right vs. wrong answer frequency below, I beg to differ. People seem to see `void (*` and immediately conclude this is a function pointer while they start hunting for an argument list to digest, not seeing the second `(`, the extra `)`, and the trailing `(int)`. In this case, `signal` is a function, not a function pointer, and the syntax is anything-but-simply unless you're very comfortable with c decls. – WhozCraig Mar 25 '17 at 09:22
  • @WhozCraig I disagree about the pointer-behind-typedef thing. You could easily write `typedef void sig_fn(int); sig_fn *signal(int sig, sig_fn *handler);` without hiding pointers. :-) – melpomene Mar 25 '17 at 09:54
  • @melpomene To each his own. I believe callback function pointers and opaque handle libraries are the two places (and honestly the *only* two places) where pointer hiding in typedefs make sense. Regarding doing it without them, sure you can, and to that I defer to the single-responsibility-principle. Always nice to see someone with a different view than mine. Thanks. – WhozCraig Mar 25 '17 at 09:58

4 Answers4

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

signal is a function that takes int and a pointer to a function(that takes integer as argument and returns void) and returns pointer to a function(that take integer as argument and returns void)

Reference link : https://www.tutorialspoint.com/c_standard_library/c_function_signal.htm

msc
  • 33,420
  • 29
  • 119
  • 214
1

func is a function pointer that takes an int as parameter and returns nothing.

void (*func)(int)

Signal is a function that takes int and func for parameter:

signal(int sig, void (*func)(int)) // calling it x

Signal returns a function pointer from the above form, taking int for argument and returns nothing:

void (*x)(int)
SMFSW
  • 286
  • 1
  • 2
  • 10
0

To me, I like to explain it from inside to outside.

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

First you need to know the syntax of function pointer, when you see void (*func)(int), you should be aware that this is a function pointer which can point to the function which takes an int as parameter.

Then the second part void (*signal(int sig, ...))(int), you can see that there is a invocation of signal, and also the syntax of function pointer. Thus, the signal is a function which returns a function pointer, so that it can coordinate with the function pointer syntax void (*signal(..))(int)

PS. I think you may learn about how to use typedef with function pointer

Community
  • 1
  • 1
Jiahao Cai
  • 1,222
  • 1
  • 11
  • 25
0

Looking at it from the other side, how do you create such a declaration? You can do it by following two rules:

  1. To declare a function (with some argument list) returning T, first declare func as T. Then add the parameter list (wrapped in parentheses) after func.
  2. To declare a pointer to T, first declare ptr as T. Then add (* before and ) after ptr. Optionally, if the token following (*ptr) is not ( or [, you can remove the parens you just added (leaving just *ptr).

(func and ptr are just placeholders. You can use any identifier you want.)

signal is a function (we'll deal with the parameters later) returning a pointer to a function (of some parameters) returning void. To declare this, we need to start at the end and declare signal as void (yes, I know that's not allowed):

void signal;

The next step is "... function (of some parameters) returning void", so we apply rule #1:

void signal( /* some parameters */ );

The next step is "... a pointer to [that function]", so we apply rule #2:

void (*signal)( /* some parameters */ );

We can't remove the parens in (*signal) because the following token is (.

The next step is "... a function (we'll deal with the parameters later) returning [that pointer]", so we apply rule #1:

void (*signal( /* to be dealt with later */ ))( /* some parameters */ );

That's the complete skeleton. Now let's take a look at the parameter lists.

The some parameters part is what the function-that-signal-returns-a-pointer-to accepts. Which is just an int:

void (*signal( /* to be dealt with later */ ))( int );

The to be dealt with later part is what signal itself takes, which is two parameters:

  1. a signal number, int
  2. a signal handler, a pointer to a function (taking an int) returning void

#1 is easy: int sig.

#2 can be done "backwards" again:

void func;  // func is void

Applying rule #1:

void func(int);  // func is a function returning void

Applying rule #2:

void (*func)(int);  // func is a pointer to a function returning void

Plugging our parameters in the declaration of signal finally gives us:

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

This is exactly the declaration you were struggling to decipher: signal is a function (taking sig, an int, and func, a pointer to a function taking an int and returning void) returning a pointer to a function taking an int and returning void.

This answer might not make it easier to read those declarations, but now you'll be able to create your own monstrosities of this kind. :-)


PS: If you want to incorporate arrays as well, there's a third rule:

  1. To declare an array (of size N) of T, first declare arr as T. Then add [N] after arr.
melpomene
  • 84,125
  • 8
  • 85
  • 148