ian@r6.uucp (Ian Cottam) (10/22/89)
Some observations on the little program below (following some recent discussions in this group): _______________________ #include <stdio.h> int main() { char ch; while ( ! feof(stdin) ) { ch= getchar(); putchar(ch); } return 0; } ______________________ 1) This program runs as quickly as the ``((ch= getchar()) != EOF)'' version (on my SUN3 with gcc). 2) Although in this specific example the variable ch is redundant, I include it to show that declaring it to be a char is quite sensible given the feof() test. Thus a common error in C code -- a colleague of mine even found this error in K&R first edition -- the sign extension (or not) character comparison with EOF is avoided. 3) The, to my mind, awful idiom in 1) above is avoided, with the extra benefit that the ``(ch= getchar() != EOF)'' slip up will not be made. 4) This code is completely portable to implementations that have: sizeof(char) == sizeof(int) 5) Although, to my mind, the above is a compelling argument to abandon the explicit test for EOF, everyone reading this newsgroup (except me of course :-) ) will ignore it! ----------------------------------------------------------------- Ian Cottam, Room IT101, Department of Computer Science, University of Manchester, Oxford Road, Manchester, M13 9PL, U.K. Tel: (+44) 61-275 6157 FAX: (+44) 61-275-6280 Internet: ian%cs.man.ac.uk@nss.cs.ucl.ac.uk JANET: ian@uk.ac.man.cs UUCP: ..!mcvax!ukc!man.cs!ian ----------------------------------------------------------------- ----------------------------------------------------------------- Ian Cottam, Room IT101, Department of Computer Science, University of Manchester, Oxford Road, Manchester, M13 9PL, U.K. Tel: (+44) 61-275 6157 FAX: (+44) 61-275-6280 Internet: ian%cs.man.ac.uk@nss.cs.ucl.ac.uk JANET: ian@uk.ac.man.cs UUCP: ..!mcvax!ukc!man.cs!ian -----------------------------------------------------------------
peter@ficc.uu.net (Peter da Silva) (10/24/89)
> while ( ! feof(stdin) ) { > ch= getchar(); > putchar(ch); > } > 5) Although, to my mind, the above is a compelling argument to abandon the > explicit test for EOF, everyone reading this newsgroup (except me of > course :-) ) will ignore it! The fact that it appends a 0xFF byte to the output is, of course, quite irrelevant. I did exactly the same thing (though in a much more complex loop) about eight years ago. It didn't take more than 15 minutes to find it, but I'd already posted the program on a local CP/M bulletin board so it took a little longer to get over the embarrasment. If CP/M didn't use ^Z as EOF it would have been a much quicker fix. -- Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation. Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-' "I feared that the committee would decide to go with their previous 'U` decision unless I credibly pulled a full tantrum." -- dmr@alice.UUCP
ark@alice.UUCP (Andrew Koenig) (10/24/89)
In article <266@m1.cs.man.ac.uk>, ian@r6.uucp (Ian Cottam) writes: > Some observations on the little program below (following some recent > discussions in this group): > > #include <stdio.h> > int > main() > { > char ch; > while ( ! feof(stdin) ) { > ch= getchar(); > putchar(ch); > } > return 0; > } [several reasons that this program is a better way of testing for end of file than ((ch=getchar()) != EOF), ending in the following:] > 5) Although, to my mind, the above is a compelling argument to abandon the > explicit test for EOF, everyone reading this newsgroup (except me of > course :-) ) will ignore it! The trouble, of course, is that this program doesn't work! The feof() test determines whether a call to getc() has already returned EOF, not whether the next call to getc() will. Thus the last time through the loop, the feof() test will return `false,' the getchar() call will return EOF, and the call to putchar() will write out a single extra character whose value is the truncation of EOF. I agree that the above is a compelling argument, but I suspect we may not have quite the same view of its direction. -- --Andrew Koenig ark@europa.att.com
tps@chem.ucsd.edu (Tom Stockfisch) (10/24/89)
In article <266@m1.cs.man.ac.uk> ian@r6.UUCP (Ian Cottam) writes: > char ch; > while ( ! feof(stdin) ) { > ch= getchar(); > putchar(ch); > } >1) This program runs as quickly as the ``((ch= getchar()) != EOF)'' > version (on my SUN3 with gcc). The problem with this version is that feof() does not test for an error condition on stdin, whereas getc() will return EOF on i/o error. So your program might loop infinitely if there is an i/o error. The above code fragment will also fill up the disk with (char)EOF if chars are unsigned. -- || Tom Stockfisch, UCSD Chemistry tps@chem.ucsd.edu
ian@r6.uucp (Ian Cottam) (10/24/89)
In article <266@m1.cs.man.ac.uk> ian@r6.UUCP I (Ian Cottam) write: >Some observations on the little program below (following some recent >discussions in this group): >_______________________ >#include <stdio.h> > >int >main() >{ > char ch; > while ( ! feof(stdin) ) { > ch= getchar(); > putchar(ch); > } > > return 0; >} >______________________ Whoops! Red face! Is this any better (he says cautiously)? _______ #include <stdio.h> int main() { char ch; for(;;) { ch= getchar(); if ( feof(stdin) || ferror(stdin) ) break; else putchar(ch); } return 0; } _________ ----------------------------------------------------------------- Ian Cottam, Room IT101, Department of Computer Science, University of Manchester, Oxford Road, Manchester, M13 9PL, U.K. Tel: (+44) 61-275 6157 FAX: (+44) 61-275-6280 Internet: ian%cs.man.ac.uk@nss.cs.ucl.ac.uk JANET: ian@uk.ac.man.cs UUCP: ..!mcvax!ukc!man.cs!ian -----------------------------------------------------------------
frank@zen.co.uk (Frank Wales) (10/24/89)
In article <266@m1.cs.man.ac.uk> ian@r6.UUCP (Ian Cottam) writes: >Some observations on the little program below (following some recent >discussions in this group): >_______________________ >#include <stdio.h> > >int >main() >{ > char ch; > while ( ! feof(stdin) ) { > ch= getchar(); > putchar(ch); > } > > return 0; >} Unfortunately, this program may not work correctly. The manual for feof(3) states: "Feof returns non-zero when EOF has *previously* been detected reading the named input stream, otherwise zero". [my emphasis] This causes one extra getchar()/putchar() cycle to be executed after EOF before the program stops, which in turn results in passing putchar() something that probably doesn't look like EOF any more, not that putchar() has to cope with being handed EOF in any case. Pascal programmers beware. :-) Running this program on HP-UX 3.1 and SunOS 4.0.1, I always get at least one extra char at EOF, usually a space. Alternative versions of the above could be: #include<stdio.h> main() { char c=getchar(); while (!feof(stdin)) { (void)putchar(c); c=getchar(c); } return 0; } or, according to taste: #include<stdio.h> main() { for(;;) { char c=getchar(); if (feof(stdin)) return 0; (void)putchar(c); } } On the very odd occasion when I have used feof() in a loop condition, I have always ensured that it was valid to check it, if necessary by throwing in ungetc(getc(stream),stream); /* grungy hack */ ahead of it. I haven't done this too often, though, since it is rare that I need to test for end of file on a stream separate from reading the stream itself, and rarer that I can't rearrange the logic to avoid it. -- Frank Wales, Systems Manager, [frank@zen.co.uk<->mcvax!zen.co.uk!frank] Zengrange Ltd., Greenfield Rd., Leeds, ENGLAND, LS9 8DB. (+44) 532 489048 x217
condict@cs.vu.nl (Michael Condict) (10/25/89)
In article <266@m1.cs.man.ac.uk> ian@r6.UUCP (Ian Cottam) writes: | Some observations on the little program below (following some recent | discussions in this group): | _______________________ | #include <stdio.h> | | int | main() | { | char ch; | while ( ! feof(stdin) ) { | ch= getchar(); | putchar(ch); | } | | return 0; | } | ______________________ | | 1) This program runs as quickly as the ``((ch= getchar()) != EOF)'' | version (on my SUN3 with gcc). | | 2) Although in this specific example the variable ch is redundant, I | include it to show that declaring it to be a char is quite sensible | given the feof() test. Thus a common error in C code -- a colleague | of mine even found this error in K&R first edition -- the sign extension | (or not) character comparison with EOF is avoided. | | 3) The, to my mind, awful idiom in 1) above is avoided, with the extra | benefit that the ``(ch= getchar() != EOF)'' slip up will not be made. | | 4) This code is completely portable to implementations that have: | sizeof(char) == sizeof(int) | It is hard to argue any of the above (4) points, either for or against, since the program is just wrong. The feof test indicates whether EOF has PREVIOUSLY been encountered in stdin. It does not mean that it is safe to read a char. This program always produces an extra character of output (EOF truncated to a char) that wasn't in the input. The program does, however, nicely display another disadvantage of an eof-testing predicate: it is all too easy for the eof test to be "out of sync" with the call to the input function. This happens to beginner Pascal programmers all the time. It cannot happen with an in-band EOF value. Michael Condict condict@cs.vu.nl Vrije University Amsterdam -- Michael Condict condict@cs.vu.nl Vrije University Amsterdam
dg@lakart.UUCP (David Goodenough) (10/27/89)
ian@r6.UUCP (Ian Cottam) sez: > 3) The, to my mind, awful idiom in 1) above is avoided, with the extra > benefit that the ``(ch= getchar() != EOF)'' slip up will not be made. while (EOF != (ch = getchar())) putchar(ch); NOW try leaving the parentheses off the (ch = getchar()) bit. As a side note (and as has already been observed) the general construct: if (CONSTANT == variable) will always be safer than: if (variable == CONSTANT) because CONSTANT isn't an lvalue, so the compiler complains if you put = instead of == -- dg@lakart.UUCP - David Goodenough +---+ IHS | +-+-+ ....... !harvard!xait!lakart!dg +-+-+ | AKA: dg%lakart.uucp@xait.xerox.com +---+