Home > Archive > C > March 2004 > atoi and overflow
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| RoSsIaCrIiLoIA 2004-03-26, 11:08 pm |
| Do you like atou() and atoi_()?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <time.h>
int my_delta( int (*f)(int), int c)
{if( c>=SCHAR_MIN && c<=UCHAR_MAX && c!=EOF )
return f((unsigned char) c);
return f(c);
}
#define LIMIT 100000
size_t
getline(FILE* file, char** sa, size_t* siz)
{int c;
size_t i, size;
char *k, *s;
if(file==0 || sa==0 || siz==0)
return 0;
s=*sa; size=*siz; i=0;
if(s==0 || size<=1)
{if(s==0) /* here size must be 0 */
{if((k=malloc(256)) == NULL)
{*siz = 0;
esci:
return i;
}
}
else if((k=realloc(s, 256))==NULL)
goto esci;
*sa=(s=k); *siz=(size=256); *s=0;
}
while(1)
{if(i>LIMIT)
goto label;
if( i+4 > size )
{if((k=realloc(s, i+256+3))==NULL)
{label:
s[i]=0;
return i;
}
else {*sa=(s=k); *siz=(size= i+256+3); }
}
if((c=getc(file))==EOF)
break;
s[i++]= c;
if(c=='\n') break;
}
s[i]='\0';
return i;
}
/* input [space][+]digits */
/* return a value from 0 to UINT_MAX
UINT_MAX for error */
unsigned atou(const char* s)
{unsigned n=0;
int k ;
if(s==0)
return UINT_MAX;
while( my_delta(isspace, *s) ) s++;
if( *s=='+')
s++;
if( !my_delta(isdigit, *s) )
return UINT_MAX;
while((k= *s++ - '0')>=0 && k<=9)
if( n*10.0 > UINT_MAX - k )
return UINT_MAX;
else n= 10*n + k;
return n;
}
/* input [space][+/-]digits */
/* return a value from INT_MIN to INT_MAX;
INT_MIN and INT_MAX for error */
int atoi_(const char* s)
{int n=0;
int k, sign;
if(s==0)
return INT_MAX;
while( my_delta(isspace, *s) )
s++;
if( (k=*s)=='-' || k=='+')
++s;
sign = (k=='-') ? -1: 1;
if( !my_delta(isdigit, *s) )
return sign<0 ? INT_MIN : INT_MAX;
while( (k= *s++ - '0')>=0 && k<=9 )
if( n*10.0 > INT_MAX - k )
return sign<0 ? INT_MIN : INT_MAX;
else n= 10*n + k;
return sign*n;
}
int main(void)
{char *p=0;
size_t len, size=0;
do{printf("\nInsert a number ([CTRL-Z] for end ) > ");
fflush(stdout);
if( (len= getline(stdin, &p, &size))==0 )
break;
printf("You have inserted for atou : %u\n", atou (p));
printf("You have inserted for atoi_: %d", atoi_(p));
if(p[len-1]!='\n' && !feof(stdin))
break; /* no memory for store the last '\n' */
}while(!feof(stdin));
free(p);
return 0;
}
| |
| RoSsIaCrIiLoIA 2004-03-26, 11:08 pm |
| On Thu, 25 Mar 2004 17:38:36 GMT, RoSsIaCrIiLoIA <n@esiste.ee> wrote:
>Do you like atou() and atoi_()?
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <ctype.h>
>#include <limits.h>
>#include <stddef.h>
>#include <time.h>
>
>int my_delta( int (*f)(int), int c)
>{if( c>=SCHAR_MIN && c<=UCHAR_MAX && c!=EOF )
> return f((unsigned char) c);
> return f(c);
>}
>
Have I to insert here
#undef isspace
#undef isdigit
for to prevent isspace and isdigit are macro?
> while( my_delta(isspace, *s) ) s++;
>
> if( *s=='+')
> s++;
> if( !my_delta(isdigit, *s) )
| |
|
|
| Ben Pfaff 2004-03-26, 11:08 pm |
| Emmanuel Delahaye <emdelYOURBRA@noos.fr> writes:
> In 'comp.lang.c', RoSsIaCrIiLoIA <n@esiste.ee> wrote:
>
>
> No. These functions are obsolete. Better to use strto*().
Obsolete? I've never heard of either one. They have never been
standard.
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
=& #123;0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x
7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x1f6},*p
=
b,x,i=24;for(;p+=!*p;*p/=4)switch(x=*p&3)case 0:{return 0;for(p--;i--;i--)case
2:{i++;if(1)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
| |
|
| RoSsIaCrIiLoIA <n@esiste.ee> wrote in
news:m76660drnso1cadcahb6dml45lnpssck7g@
4ax.com:
> int my_delta( int (*f)(int), int c)
> {if( c>=SCHAR_MIN && c<=UCHAR_MAX && c!=EOF )
> return f((unsigned char) c);
> return f(c);
> }
What does this have to do with "delta"? Why bother with this function
anyway? EOF doesn't fit in a char, so you won't get that in your string,
and casting anything else to (unsigned char) is harmless.
> #define LIMIT 100000
> size_t
> getline(FILE* file, char** sa, size_t* siz)
What's this have to do with anything?
> /* input [space][+]digits */
> /* return a value from 0 to UINT_MAX
> UINT_MAX for error */
> unsigned atou(const char* s)
> {unsigned n=0;
> int k ;
What does k mean?
> while((k= *s++ - '0')>=0 && k<=9)
> if( n*10.0 > UINT_MAX - k )
You're doing floating point math in a string to integer conversion?
Yuck. Why not n > (UINT_MAX-k)/10?
> /* input [space][+/-]digits */
> /* return a value from INT_MIN to INT_MAX;
> INT_MIN and INT_MAX for error */
> int atoi_(const char* s)
> {int n=0;
> int k, sign;
>
> if(s==0)
> return INT_MAX;
>
> while( my_delta(isspace, *s) )
> s++;
> if( (k=*s)=='-' || k=='+')
> ++s;
>
> sign = (k=='-') ? -1: 1;
Why are you doing assignment inside the test? Certainly not for
readability. Not for speed or brevity either, since you do two tests
when one would do. (and any optimizing compiler would make that
pointless anyway)
consider:
int sign = 1;
switch (*s)
{
case '+': ++s; break;
case '-': ++s; sign = -1; break;
}
> if( !my_delta(isdigit, *s) )
> return sign<0 ? INT_MIN : INT_MAX;
sign is uninitialized if the number doesn't begin with '-' or '+'
> while( (k= *s++ - '0')>=0 && k<=9 )
> if( n*10.0 > INT_MAX - k )
> return sign<0 ? INT_MIN : INT_MAX;
> else n= 10*n + k;
> return sign*n;
I don't think it is guaranteed that INT_MIN == -1*INT_MAX. If it's
possible that the absolute value of INT_MIN is less than INT_MAX, you
could still have overflow. The other way around is probably fairly
common, which would make it impossible to parse INT_MIN. (almost - it
would return INT_MIN from your error checking code.)
-josh
| |
| Simon Biber 2004-03-26, 11:08 pm |
| "josh" <smileyfaceswillruletheworld@yahoo.com.NOSPAM> wrote:
> RoSsIaCrIiLoIA <n@esiste.ee> wrote:
>
>
> What does this have to do with "delta"? Why bother with this function
> anyway? EOF doesn't fit in a char, so you won't get that in your string,
> and casting anything else to (unsigned char) is harmless.
ISO-8859-1's ÿ (y-umlaut) has value 255 which on typical 2's complement
systems maps to a signed char value of -1, which is also a typical value of
EOF. It would be an error to recognise this character as EOF whenever it
appears in a string.
--
Simon.
| |
| RoSsIaCrIiLoIA 2004-03-26, 11:08 pm |
| On Thu, 25 Mar 2004 21:19:57 GMT, josh
<smileyfaceswillruletheworld@yahoo.com.NOSPAM> wrote:
>RoSsIaCrIiLoIA <n@esiste.ee> wrote in
> news:m76660drnso1cadcahb6dml45lnpssck7g@
4ax.com:
>
>What does k mean?
it is a random name from my set of names
>
>You're doing floating point math in a string to integer conversion?
>Yuck. Why not n > (UINT_MAX-k)/10?
Seems to me that (UINT_MAX-k)/10 is an integer, so it loose the
fractional part. And this is not good. But with double
n > (UINT_MAX-k)/10.0
is ok?
>
>Why are you doing assignment inside the test?
I think that a = b ? c: d; is a = (b ? c: d);
if( (k=*s)=='-' )
{++s; sign=-1;}
else if(k=='+') ++s;
else sign=1;
sign = (k=*s)=='-' ? ++s, -1 :
k=='+' ? ++s, 1 : 1;
don't know
>Certainly not for
>readability. Not for speed or brevity either, since you do two tests
>when one would do. (and any optimizing compiler would make that
>pointless anyway)
yes
>consider:
>int sign = 1;
>switch (*s)
>{
>case '+': ++s; break;
>case '-': ++s; sign = -1; break;
>}
>
yes
>
>sign is uninitialized if the number doesn't begin with '-' or '+'
no, sign would be initialized
>
>I don't think it is guaranteed that INT_MIN == -1*INT_MAX. If it's
>possible that the absolute value of INT_MIN is less than INT_MAX, you
>could still have overflow. The other way around is probably fairly
>common, which would make it impossible to parse INT_MIN. (almost - it
>would return INT_MIN from your error checking code.)
Yes
>-josh
Thanks
| |
|
|
|
| RoSsIaCrIiLoIA <n@esiste.ee> wrote in
news:7sn760ljlh4n23coirpmdsbt5age2dgcsh@
4ax.com:
> On Thu, 25 Mar 2004 21:19:57 GMT, josh
> <smileyfaceswillruletheworld@yahoo.com.NOSPAM> wrote:
>
>
> it is a random name from my set of names
Ok, but someone looking at this code for the first time will have no idea
what it's for. OTOH:
unsigned atou(const char *s)
{
unsigned n = 0;
int digit;
Now just from reading the variable definitions, someone reading this code
would be able to guess that you're taking s one digit at a time to build
n. (Actually, most people would probably just avoid using an extra
variable in this function, it doesn't really add anything.)
>
> Seems to me that (UINT_MAX-k)/10 is an integer, so it loose the
> fractional part. And this is not good. But with double
> n > (UINT_MAX-k)/10.0
> is ok?
It's fine to lose the fractional part, you don't need it. Suppose that
UINT_MAX is 12345 on your system. You want to accept "12345" and reject
"12346"
(12345 - 5) / 10 = 1234, n = 1234: ok.
(12345 - 6) / 10 = 1233, n = 1234: reject.
>
> I think that a = b ? c: d; is a = (b ? c: d);
Sorry, I meant in the line above, if ( (k=*s) ... I quoted down to this
line to show the extra test.
>
> no, sign would be initialized
Oh, I'm sorry, I misread something.
-josh
| |
| Dave Thompson 2004-03-29, 3:30 am |
| On Thu, 25 Mar 2004 18:04:51 GMT, RoSsIaCrIiLoIA <n@esiste.ee> wrote:
[color=darkred]
[color=darkred]
> Have I to insert here
>
> #undef isspace
> #undef isdigit
>
> for to prevent isspace and isdigit are macro?
>
[color=darkred]
No. If they are macros, they must be "function-like" macros, that is,
macros with parameters, and as such are invoked only if the name is
followed by a left parenthesis, then arguments and a right paren. The
name with no left paren is left unchanged by preprocessing and (thus)
guaranteed to get you the real function.
That said, you aren't accomplishing anything with 'my_delta' that
can't be done just as well by putting a cast to unsigned char in the
normal inline (possibly macro) invocation of is<whatever>.
<OT>English nits: Native speakers, except for some educated people
being arch or pretentious, don't make "I have to" into a question as
"Have I to"; the common form is "Do I have to". Or to avoid this
issue, use "I must" which becomes "Must I". And you don't need "for to
prevent", just "to prevent", but you do need to use the participle
(more specifically gerund IIRC) "being", and the plural "macros".
- David.Thompson1 at worldnet.att.net
|
|
|
|
|