Prev: problem analysis chart
Next: Please help!
From: CBFalconer on 11 Nov 2007 19:57 Richard Harter wrote: > .... snip ... > > where I assume that the return is 0 if a line was read properly > and a code value if it fails in some way. This adds error > returns for a modest price in complexity. It has the same built > in automatic inefficiencies. It also steps on one of C's little > awkwardnesses, namely the convention that 0 is false and non-zero > is true. IMNSHO this is an ancient mistake; generally speaking > there usually is only one way to succeed and many ways to fail. > It would have better to do it the other way around. However it > is a convention cast is three billion year old granite so there > is nothing to be done about it. No, the thing is that there is only one signal needed for 'OK', but it is quite possible to return various error forms. The 0 == OK matches this. It is a general practice in the standard library, and avoids returning a separate error value. -- Chuck F (cbfalconer at maineline dot net) <http://cbfalconer.home.att.net> Try the download section. -- Posted via a free Usenet account from http://www.teranews.com
From: David Thompson on 11 Nov 2007 21:17 On Thu, 01 Nov 2007 16:46:32 GMT, cri(a)tiac.net (Richard Harter) wrote: > On Thu, 11 Oct 2007 23:05:29 GMT, cri(a)tiac.net (Richard Harter) > wrote: > ><snip> we are throwing away information that (usually) has to be > >recomputed, namely the length of the line and, as we shall see, > >status information. If we want to add the information to our > >prototype there are several that to do it - it can be > >passed back through the calling sequence or it can be returned by > >the function. (We could also pass it to a global - ugh, don't do > >it.) My vote is to have it all returned by the function which > >means we create a struct (record) <snip> > Here I went wrong. Having a struct (record) to hold information > is plausible, but it may be overkill. Be that as it may, in a C > implementation this prototype doesn't work too well. First of all > the user has to go through the struct to access the line and the > status field. More importantly the normal usage in C would be a > while loop, e.g., > > struct fgetline_info fg; > ... > while (fg = fgetline(FILE *fptr, size_t maxsize)) {...} > > This doesn't work - the idiom requires a test on something that > can be "zero". If we convert the prototype and fg to a pointer > the code still doesn'twork. Now the problem is that when the read > is successful we don't need the status field; when the read fails > we don't have the status field. > You can do while( (fg = fgetline (...)) . status == 0 ){ ... } /* or != 0, or > 0, or whatever your semantics is */ This is not usual practice (in C), and I'd want to get some experience with it before deciding whether I PREFER it, but it definitely works. FWIW it could be argued that it's analogous to the much more idiomatic use in LISP of a multiple-valued return that silently collapses to the first value if the caller doesn't ask for the rest. <snip MANY other points> - formerly david.thompson1 || achar(64) || worldnet.att.net
From: Chris Torek on 12 Nov 2007 03:03 In article <1194651042.178648(a)news1nwk>, Eric Sosman <Eric.Sosman(a)Sun.COM> wrote: [massive snippage] > It reawakens memories of the days when interfaces >used "control blocks," ... > As you may gather, I am a big fan of small, simple >interfaces. Some people feel my adoration of simplicity >is unhealthily intense; ... There is a middle path here. Consider: char *get_a_line(FILE *file, struct whatever *control_block); where the "control_block" parameter is optional, and may be given as NULL. The "simple interface user" then writes: while ((line = get_a_line(fp, NULL)) != NULL) ... work with the line ... and ignores all distinctions between "complete" and "incomplete" lines, "ordinary EOF" and "read error", and so on. The "complex interface with control block" user creates and populates the control block, and does: while (get_a_line(fp, &cb), cb.status == OK) ... etc ... or whatever is appropriate. (Note: the above assumes that the return value used in the "simple interface" case is duplicated somewhere in the control block, in this case.) -- In-Real-Life: Chris Torek, Wind River Systems Salt Lake City, UT, USA (40�39.22'N, 111�50.29'W) +1 801 277 2603 email: forget about it http://web.torek.net/torek/index.html Reading email is like searching for food in the garbage, thanks to spammers.
From: Charlie Gordon on 12 Nov 2007 06:35 "CBFalconer" <cbfalconer(a)yahoo.com> a �crit dans le message de news: 4734F676.70BB10BF(a)yahoo.com... > Eric Sosman wrote: >> > ... snip ... >> >> As you may gather, I am a big fan of small, simple interfaces. >> Some people feel my adoration of simplicity is unhealthily >> intense; my own line-getter has been criticized for violating >> the "... but not simpler" part of Einstein's dictum. (The >> critic was someone I think highly of, so I gave his criticism >> careful thought before deciding to ignore it.) I mention all >> this to make my biases clear: the KISS principle is very >> important to me, but may not hold quite so much sway over others. > > Here is the heart of my ggets function, which more or less adheres > to your principles. The entire package, with testing code, demos, > docs, etc. is available at: > > <http://cbfalconer.home.att.net/download/> > > #include <stdio.h> > #include <stdlib.h> > #include "ggets.h" > > #define INITSIZE 112 /* power of 2 minus 16, helps malloc */ > #define DELTASIZE (INITSIZE + 16) > > enum {OK = 0, NOMEM}; The return value is poor: testing for EOF is indirect. Returning the length of the string could be useful too. > int fggets(char* *ln, FILE *f) > { > int cursize, ch, ix; Why not size_t for the size and the index ? > char *buffer, *temp; > > *ln = NULL; /* default */ > if (NULL == (buffer = malloc(INITSIZE))) return NOMEM; > cursize = INITSIZE; > > ix = 0; > while ((EOF != (ch = getc(f))) && ('\n' != ch)) { > if (ix >= (cursize - 1)) { /* extend buffer */ > cursize += DELTASIZE; > if (NULL == (temp = realloc(buffer, (size_t)cursize))) { > /* ran out of memory, return partial line */ > buffer[ix] = '\0'; > *ln = buffer; You should push the character back to the stream with ungetc(ch, f), or it will be lost. > return NOMEM; > } > buffer = temp; > } > buffer[ix++] = ch; > } > if ((EOF == ch) && (0 == ix)) { > free(buffer); > return EOF; > } > > buffer[ix] = '\0'; > if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) { > *ln = buffer; /* without reducing it */ > } > else *ln = temp; > return OK; > } /* fggets */ This function effectively calls malloc *and* realloc at least once per line successfully read: that's simple but quite inefficient. -- Chqrlie.
From: Richard Heathfield on 12 Nov 2007 06:46
Charlie Gordon said: > "CBFalconer" <cbfalconer(a)yahoo.com> a �crit dans le message de news: <snip> >> } /* fggets */ > > This function effectively calls malloc *and* realloc at least once per > line successfully read: that's simple but quite inefficient. Yeah, he's been told over and over again about that. -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |