C Community's Cavalier Attitude On Software Reliability

Richard O'keefe ok at goanna.oz.au
Wed Feb 28 21:15:02 AEST 1990


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 at haddock.ima.isc.com>,\
karl at 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 "#".  %#<fmt> would act exactly like %*<fmt> 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.



More information about the Comp.lang.c mailing list