[comp.lang.c] Must the "switch" quantity be an integer?

pardo@june.cs.washington.edu (David Keppel) (10/20/88)

[ appologies if this was just discussed ]

I want to declare a bunch of "magic" pointers, e.g., as is done in
/usr/include/signal.h:

    #define	BUFPTR		((os_t *)1)
    #define	SPTR		((os_t *)2)
     :

And do things like:

    foo[0] = BUFPTR;
    foo[1] = (os_t *) malloc (sizeof(os_t));
     :

then:

    switch (foo[i]) {
	case BUFPTR:
	    /* handle magic case #1 */
	    break;
	case SPTR:
	    /* handle magic case #2 */
	    break;
	case ...
	 :
	 :
	default:
	    normal (foo[i]);
    }

When I compile this with pcc, everything is happy.
When I compile this with gcc and turn on all of the
flags for dpANS (-ansi, -pedantic), the compiler
refuses to accept the code since "switch quantity is
not an integer".  This *is* certainly true, but isn't
what I expected.  I wasn't aware that dpANS required
the switch quantity to be an integer (or, presumably
things such as chars that can be converted to integers
implicitly).

Two questions:
(a) What are the rules?
(b) Can I do this portably without using a mass of
    if (foo[i]==BUFPTR) { ... } else if (foo[i]==SPTR)...
    code?  (Or, "*can* I do this portably?")

	    ;-D on  ( Compilo ad adsurd-bum )  Pardo
-- 
		    pardo@cs.washington.edu
    {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo

gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/20/88)

In article <6137@june.cs.washington.edu> pardo@cs.washington.edu (David Keppel) writes:
>    #define	BUFPTR		((os_t *)1)

This is quite non-portable.  ANSI C requires that there be some integral
type to which a pointer can be cast then uncast without loss of information,
but the integral type isn't necessarily int, and random integer values need
not be castable to pointers.

If you really have to have os_t*-shaped magic numbers, consider using real
data objects for them:
	static os_t dummy_buf;
	#define BUFPTR (&dummy_buf)

>(a) What are the rules?

The switch expression must be an integral expression.

>(b) Can I do this portably without using a mass of
>    if (foo[i]==BUFPTR) { ... } else if (foo[i]==SPTR)...
>    code?  (Or, "*can* I do this portably?")

One way, assuming that you use actual objects as I suggested above
and that ptrint_t is the integral type defined for pointer-to-integer
mapping for your implementation (the typedef needs to be adjusted
when porting):

	switch ( (ptrint_t)foo[i] )
		{
	case (ptrint_t)BUFPTR:

karl@haddock.ima.isc.com (Karl Heuer) (10/20/88)

In article <8706@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <6137@june.cs.washington.edu> pardo@cs.washington.edu (David Keppel) writes:
>>    #define	BUFPTR		((os_t *)1)
>
>This is quite non-portable.  ANSI C requires that there be some integral
>type to which a pointer can be cast then uncast without loss of information,
>but the integral type isn't necessarily int, and random integer values need
>not be castable to pointers.

True, except that "without loss of information" should be "and still compare
equal to the original".  You can lose information (e.g. runtime array bound
checking), but nothing that the program would be depending on.

>If you really have to have os_t*-shaped magic numbers, consider ...
>	#define BUFPTR (&dummy_buf)
>	case (ptrint_t)BUFPTR:

C'mon Doug, you know better than that.  That isn't a valid integral constant
expression.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/20/88)

In article <9711@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
-In article <8706@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
->If you really have to have os_t*-shaped magic numbers, consider ...
->	#define BUFPTR (&dummy_buf)
->	case (ptrint_t)BUFPTR:
-C'mon Doug, you know better than that.  That isn't a valid integral constant
-expression.

But it's an allowed extension (approved at September X3J11 meeting)
and is the best he'll be able to do along these lines.  There is no
fully portable way to use a switch expression for this.