checking for strtol unsuccessful conversions [duplicate] - c

This question already has answers here:
strtol using errno
(5 answers)
Closed 8 years ago.
Basically using strtol to check for unsuccessful conversions,
I am using the function
width = (int) strtol(argv[2], NULL, 10);
if (errno != 0) {
printf("Please parse integer argument");
}
using errno.h
It works when the arguments are characters, i.e.: argv[2] = e, 6, etic
But this fails to catch errors when arguments like 444r or 33f (leading numbers followed by characters) are supplied? Is there something I am missing?

You could use the second argument to strtol() to receive a pointer to the first character after the number, and check that the character is NUL (i.e. '\0').

You should use the second parameter of the function to determine where the parsing was stopped. According to the C Standard
7 If the subject sequence is empty or does not have the expected form,
no conversion is performed; the value of nptr is stored in the object
pointed to by endptr, provided that endptr is not a null pointer.
As for errno then
If the correct value is outside the range of representable values,
LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is
returned (according to the return type and sign of the value, if any),
and the value of the macro ERANGE is stored in errno.
It is important to note that if no conversion was done then endptr wilol contain the value of nptr.

Related

Convert char* to int or float with error handling [duplicate]

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Return Value
On success, the function returns the converted integral number as an int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values, INT_MAX or INT_MIN is returned.
So how I differ between atoi("poop") and atoi("0") and atoi("0000000")
Yes I can loop and check for all zeroes in case I get 0 result, but isn't there a better way?
Notice: I use ANSI C89
That's one of the reasons atoi is sometimes considered unsafe. Use strtol / strtoul instead. And if you have it use strtonum.
The function atoi is more dangerous than you might think. The POSIX standard says:
If the value cannot be represented, the behavior is undefined.
The C99 standard says this also:
7.20.1
The functions atof, atoi, atol, and atoll need not affect the value of
the integer expression errno on an error. If the value of the result
cannot be represented, the behavior is undefined.
As described by #cnicutar and #ouah, atoi can't distinguish a valid 0 from an invalid string making the strtol family better options.
But Why? and How? First understand that both atoi and strtol only convert the initial set of numbers in a string to numeric values. Any trailing non-numeric characters are simply ignored. strtol can be used to check for invalid strings because in addition to a numeric value, it also returns a pointer to the end of the numeric portion of the string. Thus if this end pointer still refers to the start of the original string, you can tell that there was an error and no characters from the string were converted.
There are a few of other subtleties, as seen in the code example:
long lnum;
int num;
char *end;
errno = 0;
lnum = strtol(in_str, &end, 10); //10 specifies base-10
if (end == in_str) //if no characters were converted these pointers are equal
fprintf(stderr, "ERROR: can't convert string to number\n");
//If sizeof(int) == sizeof(long), we have to explicitly check for overflows
if ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE)
fprintf(stderr, "ERROR: number out of range for LONG\n");
//Because strtol produces a long, check for overflow
if ( (lnum > INT_MAX) || (lnum < INT_MIN) )
fprintf(stderr, "ERROR: number out of range for INT\n");
//Finally convert the result to a plain int (if that's what you want)
num = (int) lnum;
Note: If you are sure the input string will be within the valid int range, you can eliminate lnum and simply cast strtol's return directly: num = (int) strtolen(in_str, &end, 10);
You cannot.
atoi cannot detect errors. If the result cannot be represented, atoi invokes undefined behavior. Use strtol instead of atoi.
Secure CERT coding advises to use strtol instead of atoi, read:
INT06-C. Use strtol() or a related function to convert a string token to an integer

Integer validation through conversion from char * to int

Say I have an invalid integer input to a char * where,
char *ch = "23 45"
using atoi(ch) gives 23 as the converted output, ignoring the space and 45.
I'm trying to do testing on this input. What can I do to flag it as an invalid input?
Either check the string before passing it to atoi() or use strtol(), though the latter will return long int.
With strtol(), you can check for errors:
RETURN VALUE
The strtol() function returns the result of the conversion, unless the value would underflow or overflow. If an underflow occurs, strtol() returns LONG_MIN. If an overflow
occurs, strtol() returns LONG_MAX. In both cases, errno is set to ERANGE. Precisely the same holds for strtoll() (with LLONG_MIN and LLONG_MAX instead of LONG_MIN and
LONG_MAX).
ERRORS
EINVAL (not in C99) The given base contains an unsupported value.
ERANGE The resulting value was out of range.
The implementation may also set errno to EINVAL in case no conversion was performed (no digits seen, and 0 returned).
The lack of error detection is one of the main shortcomings of the atoi() function. If that's something you need, then the basic answer is "don't use atoi()."
The strtol() function is a better alternative in pretty much every way. For your particular purpose, you can pass to it a pointer to a char *, wherein it will record a pointer to the first character in the input that was not converted. If the whole string is successfully converted then a pointer to the string terminator will be stored, so you might write
_Bool is_valid_int(const char *to_test) {
// assumes to_test is not NULL
char *end;
long int result = strtol(to_test, &end, 10);
return (*to_test != '\0' && *end == '\0');
}

How can I parse an integer but keep "0" as a valid value using strtol?

This might seem super obvious but strtol provides a response to the parsed integer -- but it's 0 on fail. What if the integer I parsed is 0?
errno is only guaranteed to be set in the case of over/underflow (to ERANGE). For other errors you must check the value of endptr. Quoting C89:
long int strtol(const char *nptr, char **endptr, int base);
If the subject sequence is empty or does not have the expected
form, no conversion is performed; the value of nptr is stored in the
object pointed to by endptr, provided that endptr is not a null
pointer.
Normally endptr is set to point to the next character in the input string after the last character converted, so if it's the equal to the beginning of the string, you can be sure no conversion has been performed. For example,
char *nptr = "not a number", *endptr;
long n = strtol(nptr, &endptr, 10);
assert(nptr != endptr); //false
POSIX contains a handy extension which also sets errno to EINVAL in this case, but this is nonstandard.
According to man strtol:
If no conversion could be performed, 0 is returned and the global variable errno is set to
EINVAL (the last feature is not portable across all platforms).
Is that not the case on you platform? If so, what platform are you on?
You can check for the presence of errno as indicated in the example here on CppReference.

strtol using errno

I have the following code:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
void main(void)
{
int data;
char * tmp;
data = strtol("23ef23",&tmp,10);
printf("%d",errno);
getchar();
}
output is 0 ...
why?
i am using visual studio 2010 C++
code must be C89 compatible.
strtol only sets errno for overflow conditions, not to indicate parsing failures. For that purpose, you have to check the value of the end pointer, but you need to store a pointer to the original string:
char const * const str = "blah";
char const * endptr;
int n = strtol(str, &endptr, 0);
if (endptr == str) { /* no conversion was performed */ }
else if (*endptr == '\0') { /* the entire string was converted */ }
else { /* the unconverted rest of the string starts at endptr */ }
I think the only required error values are for underflow and overflow.
Conversely, if the entire string has been consumed in the conversion, you have *endptr = '\0', which may be an additional thing you might want to check.
Your logic does not fit with the 'spec'.
see this
An invalid value does not necessarily set 'errno'.
(copy follows)
long int strtol ( const char * str, char ** endptr, int base );
Convert string to long integer
Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes as many characters as possible that are valid following a syntax that depends on the base parameter, and interprets them as a numerical value. Finally, a pointer to the first character following the integer representation in str is stored in the object pointed by endptr.
If the value of base is zero, the syntax expected is similar to that of integer constants, which is formed by a succession of:
An optional plus or minus sign
An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
A sequence of decimal digits (if no base prefix was specified) or either octal orhexadecimal digits if a specific prefix is present
If the base value is between 2 and 36, the format expected for the integral number is a succession of the valid digits and/or letters needed to represent integers of the specified radix (starting from '0' and up to 'z'/'Z' for radix 36). The sequence may optionally be preceded by a plus or minus sign and, if base is 16, an optional "0x" or "0X" prefix.
If the first sequence of non-whitespace characters in str is not a valid integral number as defined above, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
Parameters
str
C string containing the representation of an integral number.
endptr
Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
This parameter can also be a null pointer, in which case it is not used.
Return Value
On success, the function returns the converted integral number as a long int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values, LONG_MAX or
LONG_MIN is returned, and the global variable errno is set to ERANGE.
It has been 10 years since the question was first posted, but the problem does not age. The answers given are either out of date (yet true for their time) or a bit confusing because I had to search more.
I have seen this in a book and met this post while searching for its meaning, and while checking the page for strtol, I ended up in this page on cplusplus.com of errno macro.
Your question has 2 parts to answer here:
First lets make a note of these 2 things about errno:
1- errno can be anything during the execution of a program for no function resets it (unless your own function does so)
errno is set to zero at program startup ...
any function ... can modify its value ...
no ... function sets its value back to zero
2- one has to reset it before calling a function that may use it.
should be reset ... to zero before the call ... since ... previous ... function may have altered its value
your program is pretty small, so no function seems to be there to change it. The sole visitors of errno are main program to set it to zero, and strtol in case of any error.
Yet, your program shows errno is 0, and this is confusing because one expects 23ef23 would not be converted to a number since it includes letters in it. However, this expectation is wrong, and actually, you get a number from this string thus there is really no error here, so no change is made to errno. and this makes the second part of the answer.
you will find this definition in strtol page
... takes as many characters as possible that are valid following a
syntax that depends on the base parameter, and interprets them as a
numerical value ... a pointer to the first character following is
stored.
instead of a long explanation, this following print statement and its output will suffice to visualize that above definition:
printf("%d %d %s",data,errno,tmp);
23 0 ef23
if you set the base to 16, output would be 2354979 0 . And base 2 would give 0 0 23ef23, showing that strtol will not freak if it does not find a number. The only error it will give will be ERANGE for breaching limits:
If the value read is out of the range of representable values by a
long int, the function returns LONG_MAX or LONG_MIN (defined in
), and errno is set to ERANGE.
You have to set errno to 0 before you call strtol. Otherwise you overwrite whatever value strtol set errno to.
You have to check tmp is not the same as "blablabla" pointer.
If data == 0 and tmp == "blablabla", then the input data is in the incorrect format. errno needs not to be set by the implementation if the input data is not in the expected format.
On strtol, strtoll, strtoul, and strtoull functions C says:
(C99, 7.20.1.4p7) If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a null pointer.
(C99, 7.20.1.4p9) The strtol, strtoll, strtoul, and strtoull functions return the converted
value, if any. If no conversion could be performed, zero is returned.

atoi — how to identify the difference between zero and error?

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Return Value
On success, the function returns the converted integral number as an int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values, INT_MAX or INT_MIN is returned.
So how I differ between atoi("poop") and atoi("0") and atoi("0000000")
Yes I can loop and check for all zeroes in case I get 0 result, but isn't there a better way?
Notice: I use ANSI C89
That's one of the reasons atoi is sometimes considered unsafe. Use strtol / strtoul instead. And if you have it use strtonum.
The function atoi is more dangerous than you might think. The POSIX standard says:
If the value cannot be represented, the behavior is undefined.
The C99 standard says this also:
7.20.1
The functions atof, atoi, atol, and atoll need not affect the value of
the integer expression errno on an error. If the value of the result
cannot be represented, the behavior is undefined.
As described by #cnicutar and #ouah, atoi can't distinguish a valid 0 from an invalid string making the strtol family better options.
But Why? and How? First understand that both atoi and strtol only convert the initial set of numbers in a string to numeric values. Any trailing non-numeric characters are simply ignored. strtol can be used to check for invalid strings because in addition to a numeric value, it also returns a pointer to the end of the numeric portion of the string. Thus if this end pointer still refers to the start of the original string, you can tell that there was an error and no characters from the string were converted.
There are a few of other subtleties, as seen in the code example:
long lnum;
int num;
char *end;
errno = 0;
lnum = strtol(in_str, &end, 10); //10 specifies base-10
if (end == in_str) //if no characters were converted these pointers are equal
fprintf(stderr, "ERROR: can't convert string to number\n");
//If sizeof(int) == sizeof(long), we have to explicitly check for overflows
if ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE)
fprintf(stderr, "ERROR: number out of range for LONG\n");
//Because strtol produces a long, check for overflow
if ( (lnum > INT_MAX) || (lnum < INT_MIN) )
fprintf(stderr, "ERROR: number out of range for INT\n");
//Finally convert the result to a plain int (if that's what you want)
num = (int) lnum;
Note: If you are sure the input string will be within the valid int range, you can eliminate lnum and simply cast strtol's return directly: num = (int) strtolen(in_str, &end, 10);
You cannot.
atoi cannot detect errors. If the result cannot be represented, atoi invokes undefined behavior. Use strtol instead of atoi.
Secure CERT coding advises to use strtol instead of atoi, read:
INT06-C. Use strtol() or a related function to convert a string token to an integer

Resources