Understanding the signal.h macros ISO C definition - c

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:
"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.
"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.
"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.

Part 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
"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
"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:
They are macros, so you can test them with #if defined(SIGINT).
The numbers corresponding to SIGINT etc are positive int values.
They are distinct from each other, so SIGINT != SIGSEGV and so on for any pair of signal names listed in the standard.
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.

Related

Is it safe to cast a function pointer to another function pointer in C?

Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
typedef void (*callback)(int i, ...);
void foo() {
// something.
}
void foo2(int i, int j) {
// something.
}
int main(void)
{
callback c = (callback)&foo, c2 = (callback)&foo2;
(*c)(0); (*c2)(0,1);
return 0;
}
The cast itself is safe, but you must use the correct type when calling the function. This is what the C standard 6.3.2.3 says:
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
In your case void (*)(int i, ...) isn't compatible with either of the other functions, so this code is wildly undefined behavior. However, some compilers provide non-standard extensions for generic function pointer use with the non-prototype void foo() style. But that one in turn is obsolete C and shouldn't be used for that reason - always use void foo (void) in C and never empty parenthesis.
Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
No. The types of the two functions are not compatible with type callback, in the language specification's sense of "compatible", therefore calling either of those functions via a pointer of type callback invokes undefined behavior. Overall, non-variadic function types are never compatible with variadic ones, and in practice, many implementations use different calling conventions for one type than for the other, such that there is no plausible reason even to hope that calling a function of one variety as if it were of the other variety would have the desired effect in any consistent way.
You have several alternatives, among them:
Use different callback types for different purposes, each appropriate to its intended callback interface. This way you can avoid casting the callback functions at all. This would be my recommendation. It achieves the best type safety, and you need somehow to keep track of what the actual callback type is anyway, so that you can call it correctly.
Use a union of function pointer types. Callback specifiers assign to the appropriate member of the union, and callback callers select the appropriate member.
typedef union {
int (*unary)(int i);
int (*binary)(int i, int j);
} callback;
// ...
callback cb1 = { .unary = foo };
callback cb2 = { .binary = foo2 };
cb1.unary(1);
cb2.binary(1, 2);
You might even use a tagged union -- one that additionally carries information about which member is used. That would be a bit more complicated to use, but it would give you a means to achieve additional type safety. One of the variations on this approach would be my fallback recommendation if you need a single data type with which multiple callback types can be conveyed.
Choose a single callback type that meets all your needs. One way to do that would be to give it a parameter of type void *, by which callback functions can accept any number and type of inputs by, for example, a pointer to a suitable structure type.
typedef int (*callback)(void *);
struct one_int { int i1; };
struct two_int { int i1, i2; };
int foo(void *args) {
struct one_int *one_int = args; // ...
}
int foo2(void *args) {
struct two_int *two_int = args; // ...
}
Choose any function type as callback. Cast to that type going in, and back to the original type for calls.
Specify the callback type without a prototype. In C, if a function declaration that is not part of a definition of that function does not specify a parameter type list then that means that no information is provided about the parameters (unlike in C++, where that means that the function has no parameters). That is compatible with functions requiring any specific number of arguments -- but not variadic ones -- provided that applying the default argument promotions to the parameter types yields compatible types. Type int is a fine parameter type in that regard. The main ones that would be a problem are integer types narrower than int, plus float.
typedef int (*callback)();
This would allow exactly the usage you describe for the particular function types in your example.
callback cb1 = foo;
callback cb2 = foo2;
(*cb1)(1); // or just cb1(1)
(*cb2)(1, 2); // or just cb2(1, 2)
Contrary to another answer's claim, support for this approach does not constitute an extension to any version of the C language specification published to date. Supporting it is a requirement for conformance with any of C89, C99, C11, and C17. However, it has been declared "obsolescent" in C17, which constitutes a warning that it may be removed from some future version of the language specification. I expect that it indeed will be removed, possibly as soon as the next version of the specification, though obsolescence does not guarantee that.
No, the pointer will still point to the 'old' function (without parameters) and if you call the function, you will put variables on the stack which will never be used.
More problematic will be, if you have a pointer to the function with parameters and cast it to the function without parameters. Then, parameters will be fetched from the stack which you never put there. It is pure chance which values the program will operate on.
Note: This is the most likely behavior, but compilers are not bound to implement it this way (due to undefined behavior).
I guess you know this, but the safer way to do this sort of thing (although it's somewhat of a nuisance) is with explicit casts:
(*(void (*)(int, int))c2)(0, 1);
Here we:
take the generic "callback" function pointer c2
cast it to the correct function pointer type void (*)(int, int)
call it with the correct arguments
More problematic is your first callback, c. You're trying to call it with one integer argument 0, but you defined foo as accepting 0 arguments. So a more correct callback to foo as defined would be
(*(void (*)(void))c)();
Or if foo was supposed to take one argument of type int, that would be
(*(void (*)(int))c)(0);
And although as I said, the extra casts here can be a nuisance, this exercise illustrates their benefit: I didn't notice the mismatch between foo's definition and your callback c, until the compiler warned me about it after I inserted what I thought were the correct casts.
Without the casts, as other answers have explained, the code is unlikely to work. In particular, the attempt to make the callback type "variadic" (that is, with the ... in the prototype) does not help, and may very well hurt. These days, the calling conventions for variadic functions tend to be different from those for ordinary functions (a distinction which the ANSI/ISO C Standard has made since the beginning, although this marked a departure from K&R C). So if the compiler thinks that c2 points to a function of type void (*)(int, ...), and you call it with (0, 2), the compiler may very well use a different calling convention (the "varargs" one), and it might not be compatible with the non-varargs foo2, which is actually of type void (*)(int, int).
The bottom line is that it is safe to cast (convert) between function pointer types, but you must do it "on both ends"; that is, you must convert back to the correct type before calling. And "the correct type" must match both the actual function being called, and the actual arguments being passed.

What happens to the unspecified arguments in function()? [duplicate]

This question already has answers here:
What does an empty parameter list mean? [duplicate]
(5 answers)
Accessing the parameters passed to a function with an empty parameter list in C
(2 answers)
Closed 2 years ago.
I have been reading the difference between function() and function(void) in C, and I came to know that
an empty parameter list in a function declaration indicates that the
function takes an unspecified number of parameters
So I ran this code:
#include <stdio.h>
void fun();
int main(void)
{
fun(12, 13.22, 1234567890987654321, "wow", 'c');
}
void fun()
{
printf("What happened to those arguments?");
}
I don't understand why C allows this. All the posts I've read so far related to this say things like it's bad practice to use it, it is obsolescent, etc. Also from the above code, I think the type of those arguments is also unspecified. So I just want to know the reason behind "unspecified arguments of unspecified type":
What can be done with those arguments?
Is it possible to access those arguments within the function?
The reason for supporting the notation is historical. Before the first C standard (C89/C90), you couldn't use prototypes in C; prototypes were one of the biggest and most important features of Standard C. All function declarations, therefore, were written the 'empty parentheses' style (when they were written at all; most functions that returned int were not declared at all). The type void was also added in C89/C90, though some compilers supported it before the standard was finalized.
Because it was crucial to the success of C89/C90 that existing code should mostly continue to work, the empty parentheses style had to be allowed by the standard. So, your code might have been written in pre-standard C as:
#include <stdio.h>
int fun(); /* This declaration would probably have been absent */
int main(void)
{
fun(12, 13.22, 1234567, "wow", 'c');
return 0; /* This was required until C99 to give reliable exit status */
}
fun(i, d, l, s, c) /* No return type - implicitly returns int */
long l; /* Defined out of sequence - bad style, but legal */
char c; /* Passed as int; converted to char in function */
char *s; /* Should define all pointer arguments */
double d; /* No definition of i; it was an int by default */
{
printf("This is what happened to those arguments:\n");
printf("i = %d\n", i);
printf("d = %f\n", d);
printf("l = %ld\n", l);
printf("s = [%s]\n", s);
printf("c = %c\n", c);
/* No return statement - don't use the value from the function */
}
For the curious: you could omit the char *s; line in the function definition, and it still compiled and produced the same output. It was a bad idea to try that, though. You could replace the line int fun(); with static fun(); and the code compiles cleanly when no diagnostics are requested.
You get no warnings even now if you compile this file (old31.c) with GCC 9.3.0 using:
$ gcc -std=c90 -o old31 old31.c
$
Your example as written is skirting around the backwards compatibility provisions. Using void means it was new code (it would not have been valid in many pre-standard C compilers because it used void). And new code should not exploit the backwards-compatibility provisions without a good reason. That was true in 1991 as well as in the current millennium (but in 1991, there were a lot more good reasons to exploit the backwards-compatibility provisions). Good pre-standard code usually listed all parameters in the order they were used. Omitted definitions and out of sequence definitions were not entirely satisfactory.
You asked:
What can be done with those arguments?
In the code in the question, nothing can be done with the arguments. The caller pushes the values onto the stack, and pops them off when the function returns. The called function is unaware of their existence and can do nothing with them.
Is it possible to access those arguments within the function?
No — not using any standard mechanism.
There is a difference between a function declaration and a function definition when there is an empty parameter list.
Section 6.7.6.3p14 of the C standard states:
An identifier list declares only the identifiers of the parameters of
the function. An empty list in a function declarator that is
part of a definition of that function specifies that the
function has no parameters. The empty list in a function
declarator that is not part of a definition of that function
specifies that no information about the number or types of the
parameters is supplied.
What this means is that this declaration:
void fun();
Means fun takes an unknown number of parameters. While this definition:
void fun()
{
printf("What happened to those arguments?");
}
Means that fun takes no parameters. So this function call:
fun(12, 13.22, 1234567890987654321, "wow", 'c');
Is invalid and invoked undefined behavior because the number of parameters in the call don't match the actual number of parameters. This is spelled out in section 6.5.2.2p6 regarding the function call operator ():
If the expression that denotes the called function has a
type that does not include a prototype, the integer promotions
are performed on each argument, and arguments that have
type float are promoted to double. These are called the default
argument promotions. If the number of arguments does not equal
the number of parameters, the behavior is undefined. If the
function is defined with a type that includes a prototype, and either
the prototype ends with an ellipsis (, ...) or the types of
the arguments after promotion are not compatible with the types of
the parameters, the behavior is undefined.If the function is
defined with a type that does not include a prototype, and
the types of the arguments after promotion are not compatible
with those of the parameters after promotion, the behavior is
undefined, except for the following cases:
one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type,
and the value is representable in both types;
both types are pointers to qualified or unqualified versions of a character type or void.
As for why this is allowed, it is legacy behavior that goes back to pre-standardized versions of C where the type of variables and the return type of functions defaulted to int and the method of declaring functions differed from what they are now.

What is the use of sigsetjmp() return value?

As part of an exercise, I have to implement a library that support the use of user level threads.
I should use the system calls sigsetjmp and siglongjmp.
Now I am struggling to understand the use of sigsetjmp return value.
If I understood right, the return value will be be the second input for the last siglongjmp (In case it is not the first sigsetjmp).
When we want to switch threads, we call sigsetjmp to keep the registers values in the CPU in some place in the memory.
Right after we will call siglongjmp In order to load some values inside the CPU registers, so our next thread can keep running from the exact spot it halted. When calling siglongjmp we also provide and integer for the next sigsetjmp return value.
If I was right so far, I don't understand what would be the use of knowing something about the last thread, which is not running anymore, and we already kept its CPU values in the memory (because the sigsetjmp returned).
Thanks in advance
The return value from sigsetjmp() tells you whether it is being called for the first time (return value 0), or whether it is returning as the result of a siglongjmp() (return value non-zero). The behaviour of sigjmp() and longjmp() is the same. The first time call sets the sigjmp_buf or jmp_buf argument to record the state of the computation so that siglongjmp() or setjmp() can use it to jump back.
Note that you should be careful about how you use sigsetjmp() and setjmp(); the contexts in which they can be used are every restricted.
C11 §7.13.1.1 The setjmp macro says:
¶4 An invocation of the setjmp macro shall appear only in one of the following contexts:
the entire controlling expression of a selection or iteration statement;
one operand of a relational or equality operator with the other operand an integer constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement;
the operand of a unary ! operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or
the entire expression of an expression statement (possibly cast to void).
¶5 If the invocation appears in any other context, the behavior is undefined.
Note, in particular, that none of the contexts where it may be used is 'on the RHS of an assignment statement'. Having pointed that out, I've never seen an assignment fail, but technically, it is invoking undefined behaviour to assign the result.
Also note that the C standard says explicitly that setjmp() is a macro.
The C standard does not define sigsetjmp() or siglongjmp() — they are POSIX extensions to the C standard. However, the POSIX rules are basically the same:
setjmp()
longjmp()
sigsetjmp()
siglongjimp()
One reason for this is that the construction of a good, working setjmp()/longjmp() pair is an extremely delicate piece of code.
If you can find a copy, it would be worth reading
P J Plauger The Standard C Library (1992) on the topic. Even though it is old, there is a lot of wisdom in its discussions.
The return value of sigsetjmp is the value given to the [eventual] siglongjmp 2nd argument.
By convention, this is non-zero (if siglongjmp is passed 0, it will use 1).
The value returned by sigsetjmp is how the caller distinguishes "normal" operation vs. the event/signal occurred.
The first time the return is 0. The caller will now do "normal" operations.
When the siglongjmp is called, the stack is reset to the point of the sigsetjmp call. But, the return value will be non-zero, telling the caller that the event triggered and the caller should do "abort" processing.
The non-zero value in question [again] comes from the 2nd argument to siglongjmp. It can be any non-zero value. Thus, we can use it as an "abort" type code. (e.g.) It could be the signal number that occurred if we wish.
Or, any value: (e.g.) enum { ABORT_NOFILE = 100, ABORT_NOMEM, ABORT_BECAUSE_ITS_TUESDAY }; that the two invokers/callers agree on.
Anyway, here's some code to illustrate:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
sigjmp_buf jmpbuf;
int termval = 23;
void
handler(int sig)
{
siglongjmp(jmpbuf,termval);
}
int
main(void)
{
#if 0
int retval;
#else
volatile static int retval;
#endif
signal(SIGALRM,handler);
retval = sigsetjmp(jmpbuf,1);
if (! retval) {
alarm(5);
printf("running normally ...\n");
// do something useful ...
while (1);
}
else {
printf("signal occurred -- retval=%d\n",retval);
}
return 0;
}

What is the purpose of (void)variable in C? [duplicate]

This question already has answers here:
What does (void)var actually do?
(4 answers)
Closed 3 years ago.
I am reading this book and I have come across this code:
static void
task1(void *args) {
int i;
(void)args;
for (;;) {
gpio_toggle(GPIOC,GPIO13);
for (i = 0; i < 1000000; i++)
__asm__("nop");
}
}
I understand all (relatively) except for line 5. What is (void)args; doing?
args is not used in the function body, and I know that if an argument is not used then one could write
static void
task2(void *args __attribute((unused))) {
// code here
}
which is not being done here. So what is (void) written like that doing?
In general when one does not use an function argument, the compiler is likely to warn you about it. After all if you aren't going to use it why put it there in the first place?
In effect it is an artificial use of the argument that does nothing useful other than telling the compiler you know what you are doing, so "Shatupalready with the warning!"
(void) args works on all of the platforms that I have seen. I believe the __attribute((unused)) is a gcc specific thing.
Every expression has a type. Any expression can be turned into a statement by adding a semicolon. If an expression-statement yields a non-void value, that value is discarded.
Compilers will often warn about a value being discarded. Even a simple case like
printf("hello world\n");
quietly discards the int value returned by printf; a compiler warning might remind the programmer to test that value and take some action if it indicates that the call failed. (Most compilers will not warn in this particular case, since printf calls are usually used in a statement context, with the result ignored.)
Casting an expression to type void discards the result, but it does so explicitly. This is likely to silence a compiler warning.
As far as the language is concerned, a (void) cast converts a result to type void, which is equivalent to discarding that result. From a programmer's point of view, a (void) cast can silence a warning that a value is not used, since you're explicitly ignoring it and asserting to the compiler that you know what you're doing (even if you don't).
Quoting the C standard (N1570 draft), 6.3.2.2:
The (nonexistent) value of a void expression (an expression that has
type void) shall not be used in any way, and implicit or
explicit conversions (except to void) shall not be applied to
such an expression. If an expression of any other type is evaluated as
a void expression, its value or designator is discarded. (A void
expression is evaluated for its side effects.)
and 6.2.5 paragraph 19:
The void type comprises an empty set of values; it is an
incomplete object type that cannot be completed.
It's a compiler warning (-W unused-variable or -W all) they're suppressing by using it. You are correct in that __attribute__((unused)) is a valid C macro to do what you're asking, but it's a matter of preference. It's also not supported by all C compilers.
Sources:
http://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm
https://en.cppreference.com/w/cpp/compiler_support
void is an empty data type, it can be used in a different number of situations.
A function that "returns" void doesn't return anything (and by definition is a procedure, not a function).
A void* (pointer of void) is often used as a generic pointer (a pointer to a memory address with no particular data type associated with it). The compiler will let you assign this pointer to any other pointer type without need of explicit conversion.
malloc() for example, returns void* so you can do things like int* v = malloc(sizeof(int)*10)); without need of explicitly recasting the return value of malloc() to int*.
The other way around is also true, a function that takes void* as parameter will take any pointer type without need of explicit conversion.

VOID data type in C

If i declare any variable using void, it gives error but sizeof(void) is 1.
What is reason for this?
void var; // it gives error
printf("sizeof(void) = %d", sizeof(void)); //prints 1
sizeof (void) is not valid in C and is allowed in GNU C as an extension to allow pointer arithmetic with void *.
From gcc documentation:
In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1. [...] consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
The void type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their output parameters.
Upto my knowledge, You cannot use void as datatype, as the value is true or false statement the Boolean value will be 1 by default, so, it prints 1.
c.f. Is there a specific reason why “void” was not simply defined as “typedef struct{} void” (i.e. an empty struct) with appropriate casting rules? ...
This was originally suggested by Steve Bourne in AB33/Mar 1972 for Algol68 ...
Note: Algol68 doesn't have pointer arithmetic... but array slicing is available.

Resources