1
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };

STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
    char *end;
    long  l;
    errno = 0;
    l = strtol(s, &end, base);
    if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
        return OVERFLOW;
    }
    if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
        return UNDERFLOW;
    }
    if (*s == '\0' || *end != '\0') {
        return INCONVERTIBLE;
    }
    i = l;
    return SUCCESS;
}

I'm trying to write a program that can parse strings read in from a file into integer values. While looking for a method to do this I found this piece of code above on a stackoverflow post:

How to parse a string to an int in C++?

However, I can't understand how it works. Specifically, why is the programmer checking if errno == ERANGE if errno is assigned to 0? (is ERANGE a special value? )

secondly, what does "char const *s" - in the arguments list- mean?

PS: I'm not very experienced when it comes to C++ programming.

Community
  • 1
  • 1
mahela007
  • 1,399
  • 4
  • 19
  • 29
  • 4
    1. Because `strtol` can change `errno`. 2. Read up on pointers. 3. Prefer something like `boost::lexical_cast`, which is a one-liner and a possible exception. – chris Nov 26 '12 at 16:13
  • 1
    This is C. Tagging as such might help. – andre Nov 26 '12 at 16:14
  • 1
    @ahenderson You are right, but the original question was tagged C++. Besides, from the `char const*` question I collect that OP is really trying to use C++, not C. – Gorpik Nov 26 '12 at 16:20
  • 1
    @chris - The link in the question specifically points as to why not to use *boost::lexical_cast* and makes a sound point. Not that I am saying not to use it. – DumbCoder Nov 26 '12 at 16:25
  • @DumbCoder, While I agree with the logic behind it, there's only one case I know of where it doesn't do what you'd want (making sure the whole buffer was read), so apart from that, it's a very useful solution. – chris Nov 26 '12 at 18:49

5 Answers5

4

The code is using strtol() to do the parsing. This is a standard C library function. You can find documentation on strtol() here amongst other places:

strtol() man page on die.net

The errno variable is a special global variable defined by the standard C library. If a function encounters an error it is set to an error code. So while errno is assigned zero at the start of the routine, the strtol() function will assign a new value to errno if it encounters an error. The following if-statements are checking for the overflow and underflow error conditions.

The char const *s parameter is the string to be parsed. Its a pointer to a constant (read-only) string of characters. By convention strings are terminated by a NULL byte.

Ben Kelly
  • 1,304
  • 7
  • 9
0

Whenever I have done string to int conversions in C++ I used the atoi method. There should be plenty of examples online that suit what you want to do

Enigma
  • 67
  • 1
  • 8
  • @Enigma: You should *never* use `atoi`. `atoi` provides no means for handling erroneous inputs. `atoi` exists for legacy reasons and for writing quick code sketches. It is useless in real code. In C++ you have better ways to perform the conversion. But if you have to use C-style functions, it is `strto...` group and only `strto...` group. – AnT stands with Russia Nov 26 '12 at 16:24
  • @AndreyT, You could argue the 0 return value is a form of error checking. It's just ambiguous, which is why I said no **sure** error checking. – chris Nov 26 '12 at 16:25
  • @chris: Firstly, `0` is indeed ambiguous to the point of being useless. Secondly, there a bigger problem with `atoi` - it produces undefined behavior on overflow. The same problem exists with `sscanf`. Again, `strto...` functions is the only viable way to perform the conversion. – AnT stands with Russia Nov 26 '12 at 16:26
  • @AndreyT what are the "better ways" to do the conversion in c++? – mahela007 Nov 27 '12 at 11:15
  • @mahela007: See, for example, `boost::lexical_cast` and the technique it is based upon. – AnT stands with Russia Nov 27 '12 at 15:14
0

errno is a library-provided global variable that strtol (as well as other library functions) uses to indicate error conditions. In the above code strtol could change errno after the user set it to 0. ERANGE is indeed a named constant provided by the standard library, which stands for some special value used by strtol to indicate out-of-range errors.

Your char const *s question is too vague. What specifically do you not understand in it? The const part means that the user code inside str2int will not be allowed to modify the string pointed by s. The compiler will do its best to prevent any modifying (or potentially modifying) operations on string pointed by s.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

Most of the specialness here is with errno, not the values being compared to.

errno is a global that's used by some (especially older) library functions to signal errors. You assign 0 to it (which implicitly means there's no problem). Then, if it runs into a problem, a library function can assign some non-zero value to it to tell you want went wrong.

After calling the library function, you then typically check 1) whether it's now non-zero, and 2) if so, what value it has. Based on the value that's been assigned, you can react to the type of error that arose.

I should add, however, that many uses of errno are mostly non-portable. The C standard says that errno exists, that no library function assigns 0 to errno, but not a lot more more than that. It does not specify what non-zero values any particular function may assign to it (well, it specifies some non-zero values that some functions assign, but doesn't limit assignments to those values or those functions).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • What do you mean by "does not specify"? The C standard library specification (even C89/90) does state that `strtol` (and other functions of the group) set `errno` to `ERANGE` on overflow. It is implementation-defined in case of underflow, but it is guaranteed on overflow. – AnT stands with Russia Nov 26 '12 at 16:31
0

First of all, this is clearly a C program in C++ disguise.

strtol is a function from standard C library, which does the actual work. Its doumentation may be accessed there: http://linux.die.net/man/3/strtol

All other things are just preliminaries and checks.

errno is a special global variable from the C library which may be modified by standard functions in order to set an appropriate error code (yes, it's C legacy and this is not thread-safe). Its value may be set to values defined in standard header "errno.h".

Dmytro Sirenko
  • 5,003
  • 21
  • 26
  • Your last paragraph is wrong. `const char* s` is exactly the same as `char const* s`. You are thinking of `char* const s`, which is indeed a const pointer to mutable data. – Gorpik Nov 26 '12 at 16:24
  • 1
    Comments are intended to improve or discuss aspects of answers. If you agree that your last paragraph is a mistake, just remove it. No need to explain that in the answer itself or keep the wrong part for the record (that's what the answer history is for, if anyone is interested). – Gorpik Nov 26 '12 at 16:37