[comp.lang.c] Atomic #defines

dg@lakart.UUCP (David Goodenough) (08/11/89)

From article <15257@duke.cs.duke.edu>, by ndd@macbeth.cs.duke.edu (Ned D. Danieley):
> Another problem is:
> ...
>>? #define ENDOFFILE -1
> ...
>>?               done=ENDOFFILE;
> 
> some compilers will interpret this as the old =- assignment
> operator. this is one place where style can really make a difference:
> 
> 	done = ENDOFFILE;
> 
> is easier to read and doesn't piss off cc.

The correct solution is

1. Use <stdio.h>, and EOF, because there are no guarantees that EOF has to be
	-1: I could use -42 if the spirit so moved me.

2. #define ENDOFFILE (-1)

with the original, it is left as an excercise to see why some compilers
will barf on:

	a = x-ENDOFFILE;

With parentheses, the problem is avoided completely, so style doesn't come
into it.
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

scs@adam.pika.mit.edu (Steve Summit) (08/17/89)

In article <652@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>1. Use <stdio.h>, and EOF, because there are no guarantees that EOF has to be
>	-1: I could use -42 if the spirit so moved me.

Is this true?  Harbison and Steele (not necessarily a definitive
pANS reference, I know) imply that it is always -1; at least,
their discussion (p. 311 in the second edition) includes the
example line

	#define EOF (-1)

I agree that depending on the value is a bad idea, but it can be
easy to write code which does so.  One way is to start defining
your own error codes which might be returned, along with EOF,
from some intermediate-level input routines:

	#define ERROR (-2)

A better way (which is portable as long as you know that all
successful returns are positive) is

	#define ERROR (EOF-1)

The only trouble here is that the header file in which you
#define ERROR then ought to #include <stdio.h>, but that isn't
necessarily a good idea under old implementations...


                                            Steve Summit
                                            scs@adam.pika.mit.edu

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/17/89)

In article <13569@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>In article <652@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>>1. Use <stdio.h>, and EOF, because there are no guarantees that EOF has to be
>>	-1: I could use -42 if the spirit so moved me.
>Is this true?

Yes; EOF can be defined as any int value that differs from all
possible char values.

>	#define ERROR (EOF-1)

Don't do this.  You don't know what EOF might be defined as, so
this might not work right.

EOF belongs to the C implementation.  Invent your own symbols for
your own uses.

maart@cs.vu.nl (Maarten Litmaath) (08/18/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
\In article <13569@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
\...
\>	#define ERROR (EOF-1)
\
\Don't do this.  You don't know what EOF might be defined as, so
\this might not work right.

What should he use instead?

	#define	ERROR	(-2)

... might not work either!
-- 
  kilogram, n.: the amount of cocaine    |Maarten Litmaath @ VU Amsterdam:
         you can buy for $100K.          |maart@cs.vu.nl, mcvax!botter!maart

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/19/89)

In article <3019@solo1.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>What should he use instead?
>	#define	ERROR	(-2)
>... might not work either!

I already answered that:  He should not attempt to add his own extensions
onto the getc() extended range (characters + EOF), but should define his
own special values.  For example:
	int my_getch() {
		int	c = getchar();
		return c != EOF ? c : ferror(stdin) ? MY_ERR : MY_EOF;
	}
where MY_ERR and MY_EOF are any two distinct negative ints.

mouse@mcgill-vision.UUCP (der Mouse) (08/28/89)

In article <10765@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <13569@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>>	#define ERROR (EOF-1)
> Don't do this.  You don't know what EOF might be defined as, so this
> might not work right.

Then as far as I can see there is *no* way to (portably) choose an int
value which is not EOF and not a valid char.  Anything I can do, as far
as I can see, will (for some choice of EOF, int range, and char range)
either overflow, re-use the value of EOF, or re-use the value of some
char.

> EOF belongs to the C implementation.  Invent your own symbols for
> your own uses.

Fine.  But how?

By the way, it seems to me that the required existence of EOF implies
that it is not a legal implementation choice to make char and int
identical.  Is this true?  (Flame retardant: I didn't say "sane", I
said "legal".)

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/28/89)

In article <1625@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>In article <10765@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>> EOF belongs to the C implementation.  Invent your own symbols for
>> your own uses.
>Fine.  But how?

#include <stdio.h>
#define MY_EOF (-1234) /* presumably in some local header */
#define MY_ERR (-4321)
int MyGetChar() { int c;
return (c = getchar()) == EOF ? ferror(stdin) ? MY_ERR : MY_EOF : c; }

>By the way, it seems to me that the required existence of EOF implies
>that it is not a legal implementation choice to make char and int
>identical.  Is this true?

Since in such an implementation an int would be unable to represent
all possible values in the range of a unsigned char, as required by
the specification for some library routines, it would not be standard
conforming.

scs@hstbme.mit.edu (Steve Summit) (08/29/89)

In article <1625@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>In article <10765@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>> In article <13569@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>>>	#define ERROR (EOF-1)
>> Don't do this.  You don't know what EOF might be defined as, so this
>> might not work right.
>Then as far as I can see there is *no* way to (portably) choose an int
>value which is not EOF and not a valid char.  Anything I can do, as far
>as I can see, will... either overflow, re-use the value of EOF,
>or re-use the value of some char.

Sure there is:

	#if EOF != -2
	#define ERROR (-2)
	#else
	#define ERROR (-3)
	#endif

The only reason I didn't do this in the program that prompted the
original complaint was that I didn't want to require that
<stdio.h> be #included before the header file that was trying to
#define ERROR.  (I can't yet depend on ANSI's guarantee that
multiple #inclusions of standard header files are safe, so I
didn't have the header file in question #include <stdio.h>
itself.  It occurs to me that

	#ifndef EOF
	#include <stdio.h>
	#endif

is probably a safe way to protect against a non-idempotent
<stdio.h>.  I used to occasionally cheat and use #ifndef FILE for
this purpose, but FILE isn't necessarily a preprocesser macro and
should probably be a typedef instead.  But EOF is required to be
a macro, right?)

                                                     Steve Summit

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/30/89)

In article <13899@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>	#if EOF != -2

This assumes more than the standard guarantees about EOF.
In particular, EOF might be defined as an enumeration constant.
That's unlikely, but permitted.

karl@haddock.ima.isc.com (Karl Heuer) (08/31/89)

In article <13899@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>I didn't want to require that <stdio.h> be #included before the header file
>that was trying to #define ERROR.  (I can't yet depend on ANSI's guarantee
>that multiple #inclusions of standard header files are safe, so I didn't have
>the header file in question #include <stdio.h> itself.  It occurs to me that
>	#ifndef EOF
>	#include <stdio.h>
>	#endif
>is probably a safe way to protect against a non-idempotent <stdio.h>...)

It works correctly if the user has already done the #include, or if they omit
it entirely, but not if they do it *after* #include'g your header.  The user
needs to be warned not to do that; you can't defend against it without having
write permission to stdio.h.

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

dfp@cbnewsl.ATT.COM (david.f.prosser) (08/31/89)

In article <10867@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <13899@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>>	#if EOF != -2
>
>This assumes more than the standard guarantees about EOF.
>In particular, EOF might be defined as an enumeration constant.
>That's unlikely, but permitted.

My reading of the pANS says that EOF must be a macro defined in <stdio.h>.
However, the integral constant expression that EOF is replaced by may well
involve operators or operands that are not valid in #if directives.  The
pANS has certain macros whose replacement expression are required to be
valid #if expression, so this was not an oversight.

Dave Prosser	...not an official X3J11 answer...