I came across this piece of code and completely got lost interpreting its meaning.
#include <signal.h> void (*signal(int sig, void (*func)(int)))(int);
What is a detailed explanation for the code at line 2?
I know that void
and int
are types, the *func is a pointer for a function, and the brackets are for priority. But I still don't get the (*signal ...), the (int), and the whole thing combined together. The more detailed, the better.
Probably I've known the meaning/effect of this declaration. But I had to make some more trials to help me understand what's going on, as below:
1 #include <signal.h> 2 void (*signal)(int sig, void (*func)(int)); 3 void (*signal)(int); // then void (signal)(int) again. 4 //void (*signal(int sig, void (*func)(int)))(int); //break this line into two lines above 5 6 int main(){}
In the above code, I broke void (*signal(int sig, void (*func)(int)))(int)
into two lines. For line 3, I tried both void (*signal)(int)
and void (signal)(int)
, with the same error result that indicated that I was trying to redeclare signal
:
TestDeclaration.c:2: error: 'signal' redeclared as different kind of symbol /usr/include/signal.h:93: error: previous declaration of 'signal' was here
TestDeclaration.c:3: error: 'signal' redeclared as different kind of symbol /usr/include/signal.h:93: error: previous declaration of 'signal' was here
Now I know both the trials are incorrect ways of declaration, but why are they incorrect? Why is the original way of declaration NOT a redeclaration?
It's the declaration of a function taking an int
and a pointer to a function (taking int
returning void) and returning a pointer to a function (taking int
and returning void).
Explanation, or guide to interpretation
You can interpret by treating everything in parentheses as a single entity and then working inwards using the "declaration follows usage" rule.
void (*signal(int sig, void (*func)(int)))(int);
The entity in the brackets looks like a function taking int
and returning void
.
Stripping away the outer part:
*signal(int sig, void (*func)(int))
So, signal
takes some parameters and returns something that can be dereferenced (due to the leading *
) to form a function taking int
and returning void
.
This means signal
is a function returning a pointer to a function (taking int
and returning void
).
Looking at the parameters it takes an int
(i.e. sig
) and void (*func)(int)
which is a pointer to a function (taking int
and returning void
).
This is one of the classical examples of how convoluted C declarations can become.
To understand this declaration, it usually helps to introduce a typedef:
typedef void (*sighandler_t)(int); sighandler_t signal(int sig, sighandler_t func);
The typedef declares a pointer to a function (taking an int parameter and returning nothing). The function signal
can now be seen as a function that takes two parameters (an int and a pointer to a function) and returns a pointer to a function.
This can also be derived from the original declaration, but it takes a bit of practice. The usual way is to start at the identifier that names the outermost entity (signal
is this case):
signal
is a ...
Then you read right until you find an unmatched closing parenthesis or the end of the declaration: void (*signal
(int sig, void (*func)(int))(int)
signal
is a function taking ... returning ...
Now you can choose between parsing the parameters first, or the return value first. I will do the return value first. For that, you read backwards to find the matching open parenthesis: void
(signal( / ... */ ))(int)
`signal is a function taking ... returning a pointer to ...
Reading back and forth this way you get at successive stages:
`signal is a function taking ... returning a pointer to a (function taking ... returning ...)
`signal is a function taking ... returning a pointer to a (function taking ... returning void)
`signal is a function taking ... returning a pointer to a (function taking an int and returning void)
`signal is a function taking two parameters: (an int) and (a pointer to a function taking an int and returning void), and returning a pointer to a (function taking an int and returning void)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With