user20333834
user20333834

Reputation:

Understanding the signal.h macros ISO C definition

Here's the definition of macros defined in signal.h according to ISO C N2176_C17_finaldraft document 7.14.3:

The Macros defined are:

SIG_DFL
SIG_ERR
SIG_IGN

which expand to constant expressions with distinct values that have type compatible with the second argument to, and the return value of, the 'signal' function, and whose values compare unequal to the address of any declarable function; and the following, which expand to positive integer constant expressions with type 'int' and distinct values that are the signal numbers, each corresponding to the specified condition:

SIGABRT -> abnormal termination, such as is initiated by the abort function
SIGFPE -> an erroneous arithmetic operation, such as zero divide or an operation resulting in overflow
SIGILL -> detection of an invalid function image, such as an invalid instruction
SIGINT -> Receipt of an interactive attention signal
SIGSEGV -> an invalid access to storage
SIGTERM -> a termination request sent to the program

Here, there are three important statements regarding macros defined in signal.h:

  1. "expand to constant expressions with distinct values that have type compatible with the second argument to, and the return value of, the 'signal' function".

    My understanding: These macros are replaced by a value which has the type void (*)(int), i.e., an address to a function: which takes an int as argument and has return type similar to the return type of signal function, i.e., void.

  2. "whose values compare unequal to the address of any declarable function".

    My understanding: The address to a function returned by these Macros is not equal to any declarable function. But I'm not sure what exactly is a Declarable function.

  3. "the following, which expand to positive integer constant expressions with type 'int' and distinct values that are the signal numbers".

    My understanding: I don't understand this.

Upvotes: 1

Views: 194

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 753455

Part 1

  1. "expand to constant expressions with distinct values that have type compatible with the second argument to, and the return value of, the 'signal' function".

    My understanding: These macros are replaced by a value which has the type void (*)(int), i.e., an address to a function: which takes an int as argument and has return type similar to the return type of the signal function, i.e., void.

Your understanding has a mixture of correct and incorrect understanding. You could take a look at Understanding typedefs for function pointers in C for some more information.

The official declaration of §7.14.1.1 The signal function is:

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

However, it would be easier to understand if there was a typedef such as:

typedef void (*SignalHandler)(int signum);

so that the function could be declared as:

SignalHandler signal(int signum, SignalHandler handler);

Now, in your understanding, the SIG_DFL, SIG_ERR, SIG_IGN are indeed values of type void (*)(int) — which is the same type as SignalHandler. But the return type of the function pointers is void, but the return type of signal() is SignalHandler or void (*)(int) — not void as you state.

Part 2

  1. "whose values compare unequal to the address of any declarable function".

    My understanding: The address to a function returned by these Macros is not equal to any declarable function. But I'm not sure what exactly is a declarable function.

It means that no matter how you write a function declaration:

extern void handler(int signum);
void handler(int);
…

you cannot write a function declaration where the address of the function would equal any of the constants SIG_DFL, SIG_ERR, or SIG_IGN. This is normally achieved by using values such as 0, -1, 1 as the addresses. (These are the values used on macOS Big Sur 11.7.1; I believe they are widely used values.)

Part 3

  1. "the following, which expand to positive integer constant expressions with type 'int' and distinct values that are the signal numbers".

An 'integer constant expression' is important in C. Not all expressions that involve only constant integers are integer constant expressions — beware! You can use integer constant expressions in the dimension of arrays defined at file scope, for example, or in case labels, and various other places where you're not allowed to use other integer expressions, even if they're integer expressions involving only constant integer values.

The definition means:

  1. They are macros, so you can test them with #if defined(SIGINT).
  2. The numbers corresponding to SIGINT etc are positive int values.
  3. They are distinct from each other, so SIGINT != SIGSEGV and so on for any pair of signal names listed in the standard.
  4. The values can be passed to signal() (so you can specify how the signal is to be handled) and to raise() in Standard C and to kill() in POSIX (so that the signal is sent, which will have effects that are implementation-defined.

The names and descriptions indicate the intended use of each signal.

Upvotes: 3

Related Questions