Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!samsung!munnari.oz.au!goanna!ok From: ok@goanna.oz.au (Richard O'keefe) Newsgroups: comp.lang.c Subject: Re: C Community's Cavalier Attitude On Software Reliability Summary: not fixed in ANSI C after all Message-ID: <2922@goanna.oz.au> Date: 28 Feb 90 10:15:02 GMT References: <8147@hubcap.clemson.edu> <1990Feb26.234321.1072@utzoo.uucp> <16046@haddock.ima.isc.com> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 62 Bill Wolfe wrote: : SCANF(3S) The success of literal matches and suppressed : assignments is not directly determinable. Henry Spencer wrote: : Yup, a slightly bad design which is difficult to fix ... In article <16046@haddock.ima.isc.com>,\ karl@haddock.ima.isc.com (Karl Heuer) wrote: : Since nobody else has said it yet, I will: : Fixed in ANSI C, via the "%n" directive. Nobody else said it, because it isn't true. The explicit complaint is that "the success of literal matches and suppressed assignments is not directly determinable". As an example of this, suppose I do result = scanf("%*d%*d%*d"); Now scanf() is defined (in one manual I have) to return "the number of input items matched and assigned, or EOF if the function does not store values before it sets the end-of-file or error indicator for the stream". In this particular case, that means that precisely two outcomes are possible: 0 and EOF. It is not possible to tell how many of the %*d conversion specifiers matched something. The new %n conversion specifier tells us how many _characters_ have been processed. We _can_ use it to count the matches. Here's how: int p1, p2, p3, result; p1 = p2 = p3 = -1; /* any negative value will do */ result = scanf("%*d%n%*d%n%*d%n", &p1, &p2, &p3); if (p3 >= 0) { all three %*d items matched } else if (p2 >= 0) { first two %*d items matched } else if (p1 >= 0) { only first %*d item matched } else { no %*d items matched } It is a great improvement that this is possible, but it really doesn't count as "DIRECTLY determinable". One very simple change would have done: _add_ a new suppression character, say "#". %# would act exactly like %* except that it would be counted. Then the desired effect could be achieved: result = scanf("%#d%#d%#d"); This is all that is needed: the construct %#0c would read no characters and would not store them anywhere, but it _would_ increment the counter. So to check for the dreaded message, result = scanf("Hello%#0c world#0c"); would set result to 2 if the whole of "Hello world" was matched. Presumably the ANSI C committee considered and rejected some such proposal. It would be intersting to know why (no prior art, perhaps). It doesn't bother me, because I find that using my own "parsing" functions and the standard conversion functions (strtol, strtod, strtoul) is - easier for C to check (no varargs functions) - easier for C to optimise (no pointers needed) - more flexible (e.g. I can allow "#..\n" comments) - as portable as getc() - and *still* 20% or more faster than typical UNIX implementations of scanf(). Just because something is in the standard doesn't mean you _have_ to use it.