C language > Expert questions
How can I test a numeric string overflow?
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