In article <87************ @bsb.me.uk>
Ben Bacarisse <be********@bsb .me.ukwrote:
>[Aside. I feel I must "come clean". Until today I did not know that
strtoul accepted "-123" as a valid number[1]. Of course it does the
right thing with it but you can't tell, from the result alone, that
the input was not 4294967173[2]. If I'd been more clued up on that at
the start, I'd have advised the use of strtol right from the get-go.]
[1] Well, I might have known. It seems a strangely familiar
discovery, but it was not up there at the front on my brain where it
was needed to give the best advice. The OP is validating input and,
for most application end users, C's interpretation of (unsigned
long)-123 is just baffling. strtoul is not the right tool.
[footnote 2 snipped] It probably is true that strtoul() is not
as commonly useful as strtol(), and I am not sure *why* strtoul
is specified as allowing explicit signs, but if you wish to
forbid signs, the method Peter Nilsson showed (elsethread) is
probably the simplest. That is, just call strtoul() as normal,
but add to the "number was valid" checks a call to strchr() to
check for '-' (and '+' as well, if you wish to forbid that too).
If you are going to check for more than one "forbidden" character
-- e.g., for both + and -, and/or for leading whitespace -- you
can use strpbrk(). That is, instead of:
/* Assumes:
"char *input" pointing to the input,
"char *ep" which need not be initialized,
"int base" which should be 10 or 0 or whatever,
"unsigned long result",
and of course the appropriate #include directives. */
errno = 0;
result = strtoul(input, &ep, base);
if ((result == ULONG_MAX && errno == ERANGE) || /* value too large */
ep == input || /* no value supplied (so result==0) */
*ep != '\0' || /* trailing junk after value */
strchr(input, '-') != NULL || /* contained leading - sign */
strchr(input, '+') != NULL /* contained leading + sign */) {
... do something about bad input ...
}
you can do:
if ((result == ULONG_MAX && errno == ERANGE) || ep == input ||
*ep != '\0' || strpbrk(input, "-+") != NULL)) {
... do something ...
}
If you want to reject whitespace, *and* want to handle locales,
the problem is a bit harder. While ' ', '\t', '\b', '\r', '\n',
and '\f' are all whitespace, there may be additional characters
for which isspace() would return true. In this case you cannot
easily use strchr() or strpbrk(); you will be better off with a
test for isspace(). (But you can just check the first character
since strtoul() allows only *leading* whitespace.)
(It is of course possible to do the "forbidden characters" test up
front, but since you must do the "value out of range" test *after*
calling strtoul() -- or indeed any of the strto* family -- and most
programs need not handle errors as fast as possible, it is safe
enough to pile them all up at the end like this.)
--
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: gmail (figure it out)
http://web.torek.net/torek/index.html