In the loop, you've got the current value of the integer determined by the first digits. You're about to do:
curval = curval * 10 + digit; // digit converted from '0'..'9' to 0..9 already
You can test for overflow with:
if (curval > UINT32_MAX / 10 || (curval == UINT32_MAX / 10 && digit > UINT32_MAX % 10))
...overflow would occur...
else
curval = curval * 10 + digit; // overflow did not occur
The division and modulus operations are compile time operations, not run time operations.
One advantage of this approach over using a 'larger than 32-bit unsigned integer for the calculation' is that it can be extended to work with bigger integers — with 64-bit integers and uintmax_t
integers — by changing the constant from UINT32_MAX to UINT64_MAX or UINTMAX_MAX. That's all that's necessary (other than changing the variable types, of course).
The same basic test also works for signed types, but there's an added complication. It's easier to use 16-bit integers for demo purposes (fewer digits to type and think about), so I'm switching to 16-bit two's-complement short
with:
USHRT_MAX
= 65535
SHRT_MAX
= 32767
SHRT_MIN
= -32768
The problem is that the short
type can store -32768 but the largest positive value you can accumulate is 32767. For all values except SHRT_MIN, the test above would work fine. There are ways around this dilemma. One is to store the curval
as a negative value during the calculation, and to negate it before returning if it should be positive. Then your testing might be:
if (curval < SHRT_MIN / 10 || (curval == SHRT_MIN / 10 && digit > -(SHRT_MIN / 10))
...overflow would occur...
else
curval = curval * 10 - digit; // Note subtraction!
You still have to check that curval
is not SHRT_MIN
before negating the negative value. (In theory, you should check that -SHRT_MAX != SHRT_MIN
to allow for other systems than two's complement binary; the values I quoted for the limits satisfy that condition.)
The same thinking and techniques apply to INT_MAX
, INT32_MAX
, INT64_MAX
and INTMAX_MAX
, of course.