Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Question about Linux/gcc and the signal() function prototype.

48 views
Skip to first unread message

Kenny McCormack

unread,
Nov 25, 2022, 6:39:43 AM11/25/22
to
Note: This question is very Linux and gcc specific. You've been warned!
Also, don't bother picking nits like how main() is declared or whether or
not to use the word "stack" in polite company. Thanks.

I have a small C program that looks basically like:

#define _GNU_SOURCE
#include <signal.h>

...

sighandler_t myhandler(int sig)
{
...
}

int main(void)
{
...
signal(1,myhandler);
...
}

I compile with the usual: -W -Wall -Werror
and get these errors:

$ gcc ...
MyTest.c: In function 'main':
MyTest.c:22:40: error: passing argument 2 of 'signal' from incompatible pointer type [-Werror]
signal(1,myhandler);
^
In file included from MyTest.c:7:0:
/usr/include/signal.h:102:23: note: expected '__sighandler_t' but argument is of type 'void (* (*)(int))(int)'
extern __sighandler_t signal (int __sig, __sighandler_t __handler)
^

Now, I can make this go away in either of two ways:

1) Change the call to signal to:

signal(1,(sighandler_t) myhandler);
or
2) Remove the #define _GNU_SOURCE and then:
a) Declare myhandler as "sig_t" instead of "sighandler_t".
b) Change the call to signal to:
signal(1,(sig_t) myhandler);

But the point is that in either case, a cast in the signal() call seems
to be required. Why is this?

Note that the myhandler() function is declared/defined before main(), so it
should "just work", shouldn't it?

--
Joni Ernst (2014): Obama should be impeached because 2 people have died of Ebola.
Joni Ernst (2020): Trump is doing great things, because only 65,000 times as many people have died of COVID-19.

Josef Stalin (1947): When one person dies, it is a tragedy; when a million die, it is merely statistics.

Ralf Fassel

unread,
Nov 25, 2022, 7:03:39 AM11/25/22
to
* gaz...@shell.xmission.com (Kenny McCormack)
| Note: This question is very Linux and gcc specific. You've been warned!
| Also, don't bother picking nits like how main() is declared or whether or
| not to use the word "stack" in polite company. Thanks.
>
| I have a small C program that looks basically like:
>
| #define _GNU_SOURCE
| #include <signal.h>
>
| ...
>
| sighandler_t myhandler(int sig)
| {
| ...
| }

I think that according to signal(2) that should rather be

void myhandler(int sig) {
...
}


NAME
signal - ANSI C signal handling
SYNOPSIS
#include <signal.h>
typedef void (*sighandler_t)(int);

Note that 'sighandler_t' is the typedef for the _signal handler_ (to be
used in the declaration of signal()), not the return value of the signal
handler. The return value of the signal handler is void, taking one
integer argument.

R'

Kenny McCormack

unread,
Nov 25, 2022, 7:29:06 AM11/25/22
to
In article <ygazgcf...@akutech.de>, Ralf Fassel <ral...@gmx.de> wrote:
...
>I think that according to signal(2) that should rather be
>
> void myhandler(int sig) {
> ...
> }
>
>
> NAME
> signal - ANSI C signal handling
> SYNOPSIS
> #include <signal.h>
> typedef void (*sighandler_t)(int);
>
>Note that 'sighandler_t' is the typedef for the _signal handler_ (to be
>used in the declaration of signal()), not the return value of the signal
>handler. The return value of the signal handler is void, taking one
>integer argument.

Yes, thanks. That seems to fix things.

The funny thing is that (at least on my system), nowhere in "man signal"
does it actually tell you how to declare the signal handler function (that
is, as simply "void"). You could say that this is implicit in saying that
sighandler_t is a pointer to a void function, so the thing must itself be a
void function.

That's the C way...

All of this seems to be an artifact of the fact that functions and pointers
to functions are (basically) the same thing. This isn't true for any other
type of object.

--
Trump - the President for the rest of us.

https://www.youtube.com/watch?v=JSkUJKgdcoE

Scott Lurndal

unread,
Nov 25, 2022, 11:57:50 AM11/25/22
to
gaz...@shell.xmission.com (Kenny McCormack) writes:
>In article <ygazgcf...@akutech.de>, Ralf Fassel <ral...@gmx.de> wrote:
>...
>>I think that according to signal(2) that should rather be
>>
>> void myhandler(int sig) {
>> ...
>> }
>>
>>
>> NAME
>> signal - ANSI C signal handling
>> SYNOPSIS
>> #include <signal.h>
>> typedef void (*sighandler_t)(int);
>>
>>Note that 'sighandler_t' is the typedef for the _signal handler_ (to be
>>used in the declaration of signal()), not the return value of the signal
>>handler. The return value of the signal handler is void, taking one
>>integer argument.
>
>Yes, thanks. That seems to fix things.
>
>The funny thing is that (at least on my system), nowhere in "man signal"
>does it actually tell you how to declare the signal handler function (that
>is, as simply "void"). You could say that this is implicit in saying that
>sighandler_t is a pointer to a void function, so the thing must itself be a
>void function.

FWIW, when using unix, linux or any POSIX based system, I'd recommend
using 'sigaction' rather than 'signal'.

Rainer Weikusat

unread,
Nov 27, 2022, 7:27:50 AM11/27/22
to
gaz...@shell.xmission.com (Kenny McCormack) writes:

[sighandler_t confusion]

> All of this seems to be an artifact of the fact that functions and pointers
> to functions are (basically) the same thing. This isn't true for any other
> type of object.

It's basically the same as with array types: An object which has a function
type is automatically converted to a pointer to a function when used as
argument of something. But they're nevertheless distinct. Stevens uses

typedef void sighandler(int);
sighandler *signal(int, sighandler *);

in newer editions of APUE.

Kenny McCormack

unread,
Nov 27, 2022, 8:06:34 AM11/27/22
to
In article <87lenwf...@doppelsaurus.mobileactivedefense.com>,
Yes. That makes more sense.

Probably won't ever get fixed, though.

--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
http://user.xmission.com/~gazelle/Sigs/WeekendAwayFromHome

Kaz Kylheku

unread,
Nov 27, 2022, 7:43:48 PM11/27/22
to
On 2022-11-27, Kenny McCormack <gaz...@shell.xmission.com> wrote:
> In article <87lenwf...@doppelsaurus.mobileactivedefense.com>,
> Rainer Weikusat <rwei...@talktalk.net> wrote:
>>gaz...@shell.xmission.com (Kenny McCormack) writes:
>>
>>[sighandler_t confusion]
>>
>>> All of this seems to be an artifact of the fact that functions and pointers
>>> to functions are (basically) the same thing. This isn't true for any other
>>> type of object.
>>
>>It's basically the same as with array types: An object which has a function
>>type is automatically converted to a pointer to a function when used as
>>argument of something. But they're nevertheless distinct. Stevens uses
>>
>>typedef void sighandler(int);
>>sighandler *signal(int, sighandler *);
>>
>>in newer editions of APUE.
>
> Yes. That makes more sense.
>
> Probably won't ever get fixed, though.

With sighandler defined that way, you can do this:

sighandler myhandler; // forward declaration of your handler

void myhandler(int) // ... but no way of using sighandler for defining
{
}

It has little value compared to just making a typedef for the pointer.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

Richard Damon

unread,
Nov 27, 2022, 9:40:09 PM11/27/22
to
The one advantage is if the definition disagrees with the forward
declaration, you will get a diagnostic, likely an error.

Rainer Weikusat

unread,
Nov 28, 2022, 6:47:46 AM11/28/22
to
This calls the following "famous wast lard" to mind (from the GLib
documentation)

typedef void *gpointer;

Gpointer is the GLib way of declaring a pointer to void. It looks better
than void * and is easier to use.

For people who don't belong to the I-have-to-use-C-but-hate-it!!1
faction, pointers are declared by suffixing a base type with *. Hence,
creating a typedef for the function type and deriving a pointer type
from that by suffixing it with * is consistent with the type system of
the language in general while using typedef to hide the * isn't.
0 new messages