6

If I read an integer from a istream using the >> operator, and the represented integer larger than INT_MAX then the operation just returns INT_MAX.

I am currently doing a comparison against INT_MAX to detect the overflow, but if the operation is inputted "2147483647" then it will return an error when in reality there was none and the result is valid.

Example: http://ideone.com/4bXyGd

#include <iostream>
#include <sstream>
#include <climits>

int main() {
    std::istringstream st("1234567890123"); // Try with 2147483647
    int result;

    st >> result;

    if (result == INT_MAX)
        std::cout << "Overflow!" << std::endl;
    else
        std::cout << result << std::endl;

    return 0;
}

What is the ideologically correct way to do this?

Matt
  • 7,100
  • 3
  • 28
  • 58
  • 2
    Workaround: use `long long`. –  Jun 14 '13 at 20:26
  • Declare, that valid input is up to `2147483646`, not up to `2147483647` :) (2147483647 is MAX_INT on your platfrom) – Lol4t0 Jun 14 '13 at 20:30
  • 1
    You should prefer `` over `` when using C++. `INT_MAX` is replaced by `std::numeric_limits::max()`. – Collin Dauphinee Jun 14 '13 at 20:33
  • @Lol4t0, since this is part of a scanner for C source code files, I don't think that will work. Good idea @H2CO3, not guaranteed to work (though I don't know of a system where a `long long` is the same size as an `int`, the standard does allow it). – Matt Jun 14 '13 at 20:33
  • possible duplicate: http://stackoverflow.com/questions/4442658/c-parse-int-from-string – djf Jun 14 '13 at 20:37
  • @CarlNorum, In which case INT_MAX is different. It's not that specific number that is causing problems. – Matt Jun 14 '13 at 20:44

2 Answers2

11

For general parsing failures (including the number being too large or too small) you can simply check the fail bit of the stringstream has been set. The easiest way to do this is:

if (!st) {
    std::cout << "Could not parse number" << std::endl;
}

Before C++11 there was no way to check specifically for overflow or underflow using this method. However in C++11 if the parsed value would be too large or too small small for the type, the result will be set to the largest value the type can hold (std::numeric_limits<Type>::max() or std::numeric_limits<Type>::min()), in addition to the fail bit being set.

So in C++11 to check if the value was too large or small you can do:

if (!st) {
    if (result == std::numeric_limits<int>::max()) {
        std::cout << "Overflow!" << std::endl;
    } else if (result == std::numeric_limits<int>::min()) {
        std::cout << "Underflow!" << std::endl;
    } else {
        std::cout << "Some other parse error" << std::endl;
    }
}
kgreenek
  • 4,986
  • 3
  • 19
  • 30
David Brown
  • 13,336
  • 4
  • 38
  • 55
1

The best way to do this is to read the value as a string and then convert it into an integer. During the conversion, you can catch whether the value fits within the range of the type you're converting to.

boost::lexical_cast is a good library for this. It will throw an exception if the value cannot fit in the target type.

Collin Dauphinee
  • 13,664
  • 1
  • 40
  • 71
  • If I'm going to read it into a string first then I could just do a string comparison against the max value. – Matt Jun 14 '13 at 20:37