4

Help me understand the following prototype. What is the last (int) doing?

void ( *signal(int sig, void (*handler)(int)) ) (int);
corning
  • 361
  • 5
  • 20
SeasonedNoob
  • 121
  • 1
  • 9
  • 1
    Check out [this answer](http://stackoverflow.com/a/1591492/1383051). It answers your question in great detail! – Anish Ramaswamy Apr 01 '13 at 08:05
  • possible duplicate of [Understanding typedefs for function pointers in C: Examples, hints and tips, please](http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples-hints-and-tips-ple) – Jim Balter Apr 01 '13 at 09:26
  • @JimBalter, Not too sure it's a duplicate. That question aims at understanding function pointer `typedef`s. This question aims at understanding function pointer declarations. That question's answer just answers both questions. I can understand, however, if people close this question as an answer already exists. – Anish Ramaswamy Apr 01 '13 at 09:53
  • See also: [What's the meaning of this piece of code?](http://stackoverflow.com/questions/3706704/whats-the-meaning-of-this-piece-of-code-void-signalint-sig-void-funcin) which asks explicitly about the `signal()` function prototype. – Jonathan Leffler Apr 13 '13 at 22:49

6 Answers6

10

Find the leftmost identifier and work your way out, remembering that [] and () bind before *; IOW, *a[] is an array of pointers, (*a)[] is a pointer to an array, *f() is a function returning a pointer, and (*f)() is a pointer to a function. Thus,

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

breaks down as

        signal                                          -- signal
        signal(                               )         -- is a function
        signal(    sig                        )         -- with a parameter named sig
        signal(int sig,                       )         --   of type int
        signal(int sig,        handler        )         -- and a parameter named handler
        signal(int sig,       *handler        )         --   which is a pointer
        signal(int sig,      (*handler)(   )) )         --   to a function
        signal(int sig,      (*handler)(int)) )         --   taking an int parameter
        signal(int sig, void (*handler)(int)) )         --   and returning void
       *signal(int sig, void (*handler)(int)) )         -- returning a pointer
     ( *signal(int sig, void (*handler)(int)) )(   )    -- to a function
     ( *signal(int sig, void (*handler)(int)) )(int)    --   taking an int parameter
void ( *signal(int sig, void (*handler)(int)) )(int);   --   and returning void

The signal function associates a signal (sig) with a callback function (handler), like so:

#include <signal.h>

static int interrupt = 0;

/**
 * The following function will be called when a SIGINT is
 * detected (such as when someone types Ctrl-C)
 */
void interrupt_handler( int sig )
{
  interrupt = 1;
}

int main( void )
{
  /**
   * Declare a pointer to the old interrupt handler function
   */
  void (*old_interrupt_handler )(int);

  /**
   * Save the old interrupt handler while setting the new one
   */
  old_interrupt_handler = signal( SIGINT, interrupt_handler );
  while ( !interrupt )
  {
    // do stuff until someone hits Ctrl-C
  };

  /**
   * restore the original interrupt handler
   */
  signal( SIGINT, old_interrupt_handler );
  return 0;
}
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • As a side note for people coming across this answer: [you would probably want `sigaction` instead of `signal`](http://stackoverflow.com/a/232711/912144). – Shahbaz Jan 16 '14 at 13:19
9

The whole thing declares a function called signal:

  • signal takes an int and a function pointer
    • this function pointer takes an int and returns void
  • signal returns a function pointer
    • this function pointer takes an int and returns a void

That's where the last int comes in.


You can use the spiral rule to make sense of such declarations, or the program cdecl(1).

cnicutar
  • 178,505
  • 25
  • 365
  • 392
2

As I pointed out in an answer to another recent question, one way to understand these declarations is to swap parameter lists and array declarators with the thing to their left and then read the declaration backwards. In this case that gives you

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

->

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

Which reads as "`signal is a function that takes two parameters and returns a pointer to a function that takes an int parameter and returns void". The two parameters are an int (sig) and a pointer (handler) to a function that takes an int parameter and returns void.

Or you can do the swapping mentally, which is the same as the spiral rule.

Jim Balter
  • 16,163
  • 3
  • 43
  • 66
0

void (*handler)(int); handler is pointer to a function (say Fn1) with return type voidand takes an int

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

(*signal(int sig, Fn1); This function has return type void and takes an int and function pointer as arguments.

The return type of this function, whose pointer is signal is possibly a function pointer for a function that takes an int[final int] with return type void

Suvarna Pattayil
  • 5,136
  • 5
  • 32
  • 59
0

The above prototype can be written as::

typedef void (*sig_t) (int);

sig_t signal(int sig, sig_t handler);

Now, I hope it would be clear to you.

Abhineet
  • 5,320
  • 1
  • 25
  • 43
0

it is a function returning a pointer to a function returning void..Source:" Unscrambling C Declarations " in DEEP C SECRETS

Darshan Shah
  • 57
  • 1
  • 7
  • A side note: If you ever get to read _Deep C Secrets_, bear in mind that the book is extremely old, and most of its rants aren't valid even in C89. – Shahbaz Jan 16 '14 at 13:20