Jack said:
Jack Klein wrote:
[...]
The general consensus here, which I agree with, is that the
*scanf() functions are best avoided by all except extreme
experts on their use. If non-experts avoid them, the will
never become extreme experts, making the point moot.
I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful. fgets()/sscanf()
make a good combination.
As Ben already pointed out, all the members of *scanf() produce
undefined behavior if the result of a numeric conversion is out
of range for the destination type.
Which means to use them safely, you need to pre-check the numeric
digits before converting. If you are going to check them by hand,
you might as well do the conversion yourself, it takes little
additional effort.
Now fgets() and { strol(), strtod(), strtoul(), strtoll(),
stroull() } make a robust combination.
The only problem with that is that you have to assign a buffer. I
have published some routines which operate directly on the input
stream, and need no buffers (as does scanf). However my routines
are not variadic, and do not involve loading a large interpreter
system. They also have comprehensive error reporting, and do such
things as absorbing a complete numeric field even when the value
overflows. These are worthwhile considerations, especially in a
resource starved embedded system.
The following is a sample of the routines:
/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns true for error, false for noerror
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error, zero, and the following getc returning
* \n indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: This specifically forbids a leading '+' or '-'.
* Peculiarity: This forbids overflow, unlike C unsigned usage.
* on overflow, UINT_MAX is returned.
*/
int readxwd(unsigned int *wd, FILE *f)
{
unsigned int value, digit;
int status;
int ch;
#define UWARNLVL (UINT_MAX / 10U)
#define UWARNDIG (UINT_MAX - UWARNLVL * 10U)
value = 0; /* default */
status = 1; /* default error */
do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch)); /* skipblanks */
/* while (isblank((UCHAR)ch)); */ /* for C99 */
if (!(EOF == ch)) {
if (isdigit((UCHAR)ch)) /* digit, no error */
status = 0;
while (isdigit((UCHAR)ch)) {
digit = (unsigned) (ch - '0');
if ((value < UWARNLVL) ||
((UWARNLVL == value) && (UWARNDIG >= digit)))
value = 10 * value + digit;
else { /* overflow */
status = 1;
value = UINT_MAX;
}
ch = getc(f);
} /* while (ch is a digit) */
}
*wd = value;
ungetc(ch, f);
return status;
} /* readxwd */
--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html