[comp.std.c] proper semi-portable use of signal

guido@cwi.nl (Guido van Rossum) (03/26/91)

I have some code that uses signal().  Nothing spectacular, e.g.:

	#include <signal.h>
	...
	void (*sigsave)();
	sigsave = signal(SIGINT, SIG_IGN);
	...
	signal(SIGINT, sigsave);

The compiler that comes closest to Standard C locally (gcc) warns
about this code:

	sigsave = signal(SIGINT, SIG_IGN);
	warning: argument passing between incompatible pointer types

	signal(SIGINT, sigsave);
	warning: assignment between incompatible pointer types

I don't see what's wrong.  I noticed that the declaration for signal()
in <signal.h> looks as follows:

	extern void	(*signal(int, void (*) (int, ...)))(int, ...);

Is the header wrong, is gcc overly worried, or is my code wrong?

--Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
"What do you *mean* it's not in the computer!" -- Madonna

diamond@jit345.swstokyo.dec.com (Norman Diamond) (03/27/91)

In article <3223@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes:

>... the declaration for signal() in <signal.h> looks as follows:
>	extern void	(*signal(int, void (*) (int, ...)))(int, ...);

>[gcc complains about:]
>	#include <signal.h>
>	void (*sigsave)();
You did not declare void (*sigsave)(int, ...);
>	sigsave = signal(SIGINT, SIG_IGN);
>	warning: argument passing between incompatible pointer types
What is the definition of SIG_IGN in your machine's <signal.h> ?
>	signal(SIGINT, sigsave);
>	warning: assignment between incompatible pointer types
Because your sigsave must point to a non-varargs function.

>Is the header wrong, is gcc overly worried, or is my code wrong?
 Maybe (SIG_IGN?)   , Maybe / Maybe not    , AND yes

>--Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
>"What do you *mean* it's not in the computer!" -- Madonna
It's in the soft ware.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

guido@cwi.nl (Guido van Rossum) (03/27/91)

In article <3223@charon.cwi.nl> I asked:

>>... the declaration for signal() in <signal.h> looks as follows:
>>	extern void	(*signal(int, void (*) (int, ...)))(int, ...);
>>
>>[gcc complains about:]
>>	#include <signal.h>
>>	void (*sigsave)();
>>	...
>>	signal(SIGINT, sigsave);

Norman Diamond replies:

>You did not declare void (*sigsave)(int, ...);

Indeed, but I believe my code conforms to the Standard: 4.7.1.1 lists
the second argument of signal() as void (*func)(int), not as void
(*func)(int, ...).  I thought varargs (sorry, stdarg) functions *had*
to be declared with prototypes, while for functions with fixed
argument lists, old style declarations were also acceptable.

Therefore I believe my declaration is compatible with the standard,
while the <signal.h> in question (provided by SGI) is not.  Any other
opinions?

--Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
"The life of a Repo Man is always intense"

karl@ima.isc.com (Karl Heuer) (03/28/91)

In article <3223@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes:
>Is the header wrong, is gcc overly worried, or is my code wrong?

All of the above.

The header is wrong, because the Standard specifies that signal handlers take
a single arg of type |int|; the BSDism of pretending they're variadic is not
compatible with existing practice.  (Recommended fix: make your own copy of
<signal.h> that adheres to the standard.  See enclosure.)

GCC is overly worried, but it did restrict it to a warning (rather than a
fatal error), which is appropriate behavior for a compiler when presented with
improper but fixable code.

Your code is wrong because it uses the obsolescent |void (*sigsave)()|
rather than the prototype |void (*sigsave)(int)|.  This should not cause any
problems, though, unless you're using the -Wstrict-prototypes option.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint
--------cut here--------
/*
 * Karl Heuer, 27-Mar-1991.  Public Domain.
 *
 * For systems whose native <signal.h> is not ANSI-compatible.  Imports most
 * stuff from the native <signal.h>, which we assume to be in /usr/include
 * (but we spell it with a double slash because some compilers warn about
 * including from /usr/include explicitly).  The second paragraph can begin
 * with either an include of <whoami.h>, which is expected to define
 * appropriate symbols in the _[SMCX]_* namespace, or the defines can be
 * inlined at this point.
 */
#if !defined(_H_SIGNAL)
/* some implementations misdeclare signal() */
#define signal __dummy_signal
#define sigvec __dummy_sigvec
#include "/usr//include/signal.h"
#undef signal
#undef sigvec
#define _H_SIGNAL

#include <whoami.h>
#if defined(_S_UNIX_BSD) || defined(_X_HAS_SIGVEC)
struct sigvec {
#if defined(__STDC__)
    void (*sv_handler)(int);
#else
    void (*sv_handler)();
#endif
    int    sv_mask;
    int    sv_flags;
};
#if defined(__STDC__)
extern int sigvec(int, struct sigvec const *, struct sigvec *);
#else
extern int sigvec();
#endif
#endif /* BSD mutation */

#undef SIG_DFL
#undef SIG_IGN
#undef SIG_ERR
#if defined(__STDC__)
#if defined(lint)
#define SIG_DFL         ((void (*)(int))0)
#define SIG_IGN         ((void (*)(int))0)
#define SIG_ERR         ((void (*)(int))0)
#else
#define SIG_DFL         ((void (*)(int))0)
#define SIG_IGN         ((void (*)(int))1)
#define SIG_ERR         ((void (*)(int))-1)
#endif
extern void (*signal(int, void (*)(int)))(int);
extern int    raise(int);
#else
#if defined(lint)
#define SIG_DFL         ((void (*)())0)
#define SIG_IGN         ((void (*)())0)
#define SIG_ERR         ((void (*)())0)
#else
#define SIG_DFL         ((void (*)())0)
#define SIG_IGN         ((void (*)())1)
#define SIG_ERR         ((void (*)())-1)
#endif
extern void (*signal())();
extern int    raise();
#endif
#if !defined(SIGABRT)
#define SIGABRT SIGIOT
#endif
#endif /* include guard */

gwyn@smoke.brl.mil (Doug Gwyn) (03/28/91)

In article <3223@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes:
>I don't see what's wrong.  I noticed that the declaration for signal()
>in <signal.h> looks as follows:
>	extern void	(*signal(int, void (*) (int, ...)))(int, ...);

The header is wrong (i.e. not part of a conforming implementation).
The signal handler function does NOT have a variable argument list,
but always receives precisely one argument of type int.  The ,... is
a bogus attempt to accommodate 4.2BSD-style signal handers.  If some
recent modification has been made to POSIX.1 that requires this, it
is WRONG and in general incompatible with the C standard.  (This issue
was carefully discussed at both X3J11 and P1003 levels before the
original standards were adopted.)

torek@elf.ee.lbl.gov (Chris Torek) (03/29/91)

In article <15605@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>The signal handler function does NOT have a variable argument list,
>but always receives precisely one argument of type int.  The ,... is
>a bogus attempt to accommodate 4.2BSD-style signal handers.  If some
>recent modification has been made to POSIX.1 that requires this, it
>is WRONG and in general incompatible with the C standard.

The word on the streets is that current POSIX drafts *do* require more
than one argument.

It was probably a mistake for ANSI X3.159-1989 and POSIX to attempt
to share the name `signal' and the type `signal handler' at all.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

mbrown@testsys.austin.ibm.com (Mark Brown) (03/29/91)

torek@elf.ee.lbl.gov (Chris Torek) writes:
|gwyn@smoke.brl.mil (Doug Gwyn) writes:
|>The signal handler function does NOT have a variable argument list,
|>but always receives precisely one argument of type int.  The ,... is
|>a bogus attempt to accommodate 4.2BSD-style signal handers.  If some
|>recent modification has been made to POSIX.1 that requires this, it
|>is WRONG and in general incompatible with the C standard.
|
|The word on the streets is that current POSIX drafts *do* require more
|than one argument.

POSIX 1003.1-1990 (the ISO version), Section 3.3.1.3 Signal Actions, Sub
3b - 
"The signal-catching function shall be entered as a C language function
call as follows:	void func ( int SIGNO );
where func is the specified signal-catching function and SIGNO is the signal
number of the signal being delivered."
[This is the OFFICIAL POSIX DOCUMENT for .1, not a draft.]

POSIX 1003.2 Draft 11 (the current draft) says nothing.

POSIX 1003.2a Draft 6 says nothing.

I can't speak for the .4 folks, or the multiprocessing people. I can say that
every effort is made to keep from contradicting the C standard....

-- 
Mark Brown    IBM PSP Austin, TX.     (512) 823-3741   VNET: MBROWN@AUSVMQ
MAIL: mbrown@testsys.austin.ibm.com OR uunet!testsys.austin.ibm.com!mbrown
  The nice thing about standards is that there are so many to choose from!
      DISCLAIMER: Any personal opinions stated here are just that.

gwyn@smoke.brl.mil (Doug Gwyn) (03/29/91)

In article <11568@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>The word on the streets is that current POSIX drafts *do* require more
>than one argument.

Then SC22 or whatever the appropriate coordinating agency is
should block the conflicting standard.

>It was probably a mistake for ANSI X3.159-1989 and POSIX to attempt
>to share the name `signal' and the type `signal handler' at all.

POSIX.1 deliberately relegated signal() to a different category from
sigvec().  I don't much care how sigvec() handlers are specified, but
signal() handlers MUST conform to the previously-decided interface.

diamond@jit345.swstokyo.dec.com (Norman Diamond) (03/29/91)

In article <3228@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes:

>Therefore I believe my declaration is compatible with the standard,

It was; though the combination of your declaration with the contents
of your <signal.h> (which was not provided by your processor, gcc)
yielded an invalid program.

>while the <signal.h> in question (provided by SGI) is not.

Essentially true.  The <signal.h> that was provided to you by SGI
cannot really be part of a standard-conforming implementation.
(Wierd hacks could be made to the compiler in order to get around
this, but it's not worth worrying about.)

>Any other opinions?

If you want a standard-conforming processor, you should install a
complete standard-conforming processor, not just half of one.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

gwyn@smoke.brl.mil (Doug Gwyn) (03/30/91)

In article <1991Mar29.065157.609@tkou02.enet.dec.com> diamond@jit345.enet@tkou02.enet.dec.com (Norman Diamond) writes:
>The <signal.h> that was provided to you by SGI
>cannot really be part of a standard-conforming implementation.

Yes, I in fact received e-mail from a compiler implementor at SGI
promising that this would be fixed in a forthcoming release of a
standard-conforming implementation.  (SGI's current release fails
to conform fully to the C standard in several ways, presumably
all to be fixed in the aforementioned forthcoming release.)