C language > Expert questions

How can I test a numeric string overflow?

(1/4) > >>

PaoloC13:
Hi to everybody!
I found myself facing a problem: having a string representing a numeric value, how can I define whether or not it oveflows the range of a specific type? (natively, without using any library!)

The answer I gave myself, lies below. In this example I used the type unsigned int. I would ask if anyone had a simpler and more efficient way.

thanks


--- Code: ---#include <stdlib.h>
#include <stdbool.h>

#define _SKIP_LEADING_ZEROES(s) while ( *s == '0' ) s++;
#define ISDIGIT(c) ( c > '/' && c < ':' ) // Only numeric chars.
#define UINT_MAX_DIGITS 10 // undigned int max. 4294967295 (10 digits).

#define ASCII_0 48
#define ASCII_1 49
#define ASCII_2 50
#define ASCII_3 51
#define ASCII_4 52
#define ASCII_5 53
#define ASCII_6 54
#define ASCII_7 55
#define ASCII_8 56
#define ASCII_9 57

inline size_t NumLenA(const char *restrict s)
{
size_t start = (size_t)s;
while( ISDIGIT(*s) ) s++;
return (size_t)s - start;
}

bool UIntOverflowA(const char *p)
{
_SKIP_LEADING_ZEROES(p) // It may be 00000123456789;

size_t len = NumLenA(p);

if( len > UINT_MAX_DIGITS ) return true;
if( len == UINT_MAX_DIGITS )
{
if( p[0] > ASCII_4 ) return true;
if( p[0] == ASCII_4 )
{
if( p[1] > ASCII_2 ) return true;
if( p[1] == ASCII_2 )
{
//if( p[2] > ASCII_9 ) return true;
if( p[2] == ASCII_9 )
{
if( p[3] > ASCII_4 ) return true;
if( p[3] == ASCII_4 )
{
//if( p[4] > ASCII_9 ) return true;
if( p[4] == ASCII_9 )
{
if( p[5] > ASCII_6 ) return true;
if( p[5] == ASCII_6 )
{
if( p[6] > ASCII_7 ) return true;
if( p[6] == ASCII_7 )
{
if( p[7] > ASCII_2 ) return true;
if( p[7] == ASCII_2 )
{
//if( p[8] > ASCII_9 ) return true;
if( p[8] == ASCII_9 )
{
if( p[9] > ASCII_5 ) return true;
}
}
}
}
}
}
}
}
}
}

return false;
}
--- End code ---

frankie:
Try:

--- Code: ---bool UIntOverflow(const char *p)
{
uint32_t v = 0;
while(*p && *p>='0' && *p<='9')
{
uint32_t tmp = v;
v = (v*10) + (uint32_t)(*p-'0');
if (tmp > v)
return false; //Overflow
}
return true;
}

--- End code ---

PaoloC13:
Hi frankie, thanks for your smart tip. It doesn't seem to work for me, but I tried to fix it:


--- Code: ---bool UIntSafeStr(const char *p)
{
uint32_t v = 0;
uint32_t w = 0;

while ( *p >= '0' && *p <= '9' ) // (*p != 0) inclusive.
{
if ( v > 429496729 ) // Test for v *= 10; overflow.
return false;

v *= 10;
w = (unsigned)(*p++ - '0');

if ( UINT_MAX - v < w ) // Test for addition overflow.
return false;

v += w;
}

return true;
}


UIntSafeStr("4294967295"); // Ok!
UIntSafeStr("4294967296"); // Overflow!
--- End code ---


Let me know your opinion.

frankie:
I should have fixed it at last.
Added increment of string pointer and added a check for shifting overflow.
Try it.

--- Code: ---#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

bool UIntOverflow(const char *p)
{
uint32_t v = 0;
while(*p && *p>='0' && *p<='9')
{
if (v & 0x80000000) //if last bit set
return false; //result will overflow
uint32_t tmp = v;
v = (v * 10) + (uint32_t)(*p++ -'0');
if (tmp > v)
return false; //Overflow
}
return true;
}

int main(int argc, char *argv[])
{
char *str1 = "4294967295";
char *str2 = "4294967296";

printf("%s => %s\n", str1, UIntOverflow(str1) ? "Ok" : "Overflow");
printf("%s => %s\n", str2, UIntOverflow(str2) ? "Ok" : "Overflow");

return 0;
}

--- End code ---

PaoloC13:
Great! It works properly.
Honestly, I don't understand the need of the "if ( v & 0x80000000 )" check. I was unable to find an input (to the function) that causes this exit.

At the end, it seems to work well even without it, which is your previous solution.

EDIT:
Uh! Found bad case:

--- Quote ---4294967295 => Ok
8589934590 => Ok
Press any key to continue...
--- End quote ---

Navigation

[0] Message Index

[#] Next page

Go to full version