1

After figuring out the signature of the signal function, I modified the example given by https://en.cppreference.com/w/c/program/signal.

But why can't I call the function (the signal handler) returned by the signal, instead I can call it direclty ?


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

The signal function returns a pointer to function, which is void (*)(int).

Return value

Previous signal handler on success or SIG_ERR on failure (setting a signal handler can be disabled on some implementations).

#include <signal.h>
#include <stdio.h>

void signal_handler(int signal)
{
    printf("hahahah\n");
}

int main(void)
{
    void (*f1)(int);
    f1 = signal(SIGINT, signal_handler);
    f1(3);  //Get signal SIGSEGV and failed
//    signal_handler(3); //OK
    raise(SIGINT);

}

I know it might look like a meaningless question, but the point is, f1 points to signal_handler, so calling f1(3) is just like calling signal_handler(3), I don't understand why the latter is ok but not the former, there should be not "tricks" that can make between these two calling function statments, I think.

Rick
  • 7,007
  • 2
  • 49
  • 79
  • 1
    The previous signal handler isn't necessarily a pointer to a function. – user3386109 Mar 28 '19 at 04:37
  • @user3386109 Hmm, don't understand. `signal` returns `void (*)(int)`, isn't this a pointer to function (function pointer) and can call it? – Rick Mar 28 '19 at 04:41
  • 1
    In response to the edit: `f1` does not point to `signal_handler`. It points to the **previous** signal handler. You can use `printf` with the `%p` format specifier to display `f1` and `signal_handler` and you'll see that they are different. – user3386109 Mar 28 '19 at 04:50
  • @user3386109 Yes, you're right. Thanks for telling me to use `%p` :D. – Rick Mar 28 '19 at 05:12

2 Answers2

2

There are at least 3 values that signal() can return that are not pointers to real functions:

  1. SIG_DFL — typically ((void (*)(int))0)
  2. SIG_IGN — typically ((void (*)(int))1)
  3. SIG_ERR — typically ((void (*)(int))-1)

When a program starts, the signals are either in SIG_IGN or SIG_DFL mode; you can subsequently set them to another value.

When you call f1 = signal(SIGINT, signal_handler);, you get back one of SIG_DFL and SIG_IGN — and neither of those is a pointer to a callable function (even though their type is pointer to a function of the correct type).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • What does the pattern `#define HAHA (void(*)(int)) 2` mean? I guess it's defining a function **pointer**, and the pointer's value is `2`. But I am only familiar with the pattern like `#define CONSTANT value`. I tried to imitate by doing `#define HAHA float 2.3` but failed :(. It's the first time that I see this kind of usage, could you give me some hint or may be some reference? I see 2 other questions on SO but the answer isn't really helpful. – Rick Mar 28 '19 at 05:50
  • 1
    Yes; `HAHA` is a function pointer with numeric value 2. It can't safely be used in `(*HAHA)(3)` or `HAHA(3)` — both notations work, but the former was necessary before the C89 standard was published. – Jonathan Leffler Mar 28 '19 at 05:53
  • Ok I see. Thanks. Any idea where can I find this usage on some official documentation or standard? – Rick Mar 28 '19 at 05:56
  • 1
    Well, the notation `(void (*)(int))` followed by a value is a cast of that value to a pointer to function. Casting `2` (or `1` or `0` or `-1`) is probably not officially documented anywhere. A quick scan of the C11 standard didn't reveal anything useful. – Jonathan Leffler Mar 28 '19 at 06:13
  • Ohhhh, I see. It's nothing special but casting. Ya, that's what I need. Then definitely I can do `#define HAHA (float) 2.3`. Thanksssssss! – Rick Mar 28 '19 at 06:16
1

In the following line:

f1 = signal(SIGINT, signal_handler);

f1 is assigned a previous signal handler (which is not signal_handler in the code) which may not be a pointer to a function that you can call with an int argument.

To achieve the effect you want to have define a second signal handler and assign it to f1 after the line mentioned above.

Something like this:

#include <signal.h>
#include <stdio.h>

void signal_handler2(int signal)
{
    printf("hahahah2222\n");
}

void signal_handler(int signal)
{
    printf("hahahah\n");
}

int main(void)
{
    void (*f1)(int);
    f1 = signal(SIGINT, signal_handler);
    f1 = signal(SIGINT, signal_handler2);
    f1(3);  //Success
    signal_handler2(3); //OK
    raise(SIGINT);    
}

Output:

hahahah
hahahah2222
hahahah2222

See Live Demo

P.W
  • 26,289
  • 6
  • 39
  • 76
  • So it is.. The documentation is always kinda misleading. Since I've registered a new handler, naturally I would think that **previous handler** should be the one I just register... Thank you btw ;) – Rick Mar 28 '19 at 05:16