Search code examples
csignalsfunction-pointerstypedef

Can a C function declaration have more than one identifier?


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)?


Solution

  • 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.

    Cplusplus example code:

    /* 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;
    }
    

    References:

    1. Reminder about how to typedef functions and function pointers, since this is confusing to pretty much everybody and requires re-verifying from time to time: http://www.iso-9899.info/wiki/Typedef_Function_Type