Promoting unsigned long int to long int

B

Barry Schwarz

I mean checking if the value of a variable is within some permissible
range eg. an int should always be between INT_MIN and INT_MAX range

Then use fgets and strtol or strtoul.


Remove del for email
 
P

pereges

Ok, I looked up the stroto* family of functions and have a question
with regards to that. What if I want to read a size_t variable from
the user and ensure that there is no overflow at the same time. eg:

size_t a;
char *ptr = NULL;
char *endptr;
char a_str[40]; /* User enters a string that we want to convert into a
size_t type variable */

puts("Enter the value of a\n");

if (fgets(a_str, 40, stdin) == NULL)
{
/* do the error handling */
}

if ((ptr = strchr(a_str, '\n') != NULL)
{
*ptr = '\0';
}

Now, I would like to change the string into a size_t type variable but
no strto* function allows it. Atmost I can convert to unsigned long
using strtoul function. If size_t is typedef as an unsigned long, then
there are no problems or else if its unsigned int it should overflow.
Is there any way out of this ? One way I can think of is to write a
seperate function for size_t and parse the string.

errno = 0;
a = strtoul(a_str, &endptr);

if (errno == ERANGE)
{
if (abs(a) == HUGE_VAL)
{
/* Overflow */
}
else
if (a == 0)
{
/* Underflow */
}
}
else
if (a == 0)
{
/* Conversion failed */
}
 
P

pereges

After conversion, if I check a against SIZE_MAX and SIZE_MIN..probably
that can help.
 
V

vippstar

After conversion, if I check a against SIZE_MAX and SIZE_MIN..probably
that can help.

size_t is an unsigned integer. Unsigned integers all have the same
"MIN": 0.
You *DONT* have to check for < 0. The value cannot be less than 0.
The following types need not to be checked for < 0:

unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
size_t
uintptr_t
uintmax_t
uint8_t
uint16_t
uint32_t
uint64_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
time_t
clock_t

Maybe there are more unsigned integer types in the standard, I can not
recall.
Please, do not make another post about checking for < 0... Every time
you want to check a type for < 0 look at my post and find whether it
belongs to the list or not.


.... Another Cunningham?
 
P

pereges

size_t is an unsigned integer. Unsigned integers all have the same
"MIN": 0.
You *DONT* have to check for < 0. The value cannot be less than 0.
The following types need not to be checked for < 0:

unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
size_t
uintptr_t
uintmax_t
uint8_t
uint16_t
uint32_t
uint64_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
time_t
clock_t

Maybe there are more unsigned integer types in the standard, I can not
recall.
Please, do not make another post about checking for < 0... Every time
you want to check a type for < 0 look at my post and find whether it
belongs to the list or not.

... Another Cunningham?

Ok, sorry I realize I made a mistake. I tried to run the program and
it didn't work.
 
P

pereges

size_t is an unsigned integer. Unsigned integers all have the same
"MIN": 0.
You *DONT* have to check for < 0. The value cannot be less than 0.
The following types need not to be checked for < 0:

unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
size_t
uintptr_t
uintmax_t
uint8_t
uint16_t
uint32_t
uint64_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
time_t
clock_t

Maybe there are more unsigned integer types in the standard, I can not
recall.
Please, do not make another post about checking for < 0... Every time
you want to check a type for < 0 look at my post and find whether it
belongs to the list or not.

... Another Cunningham?


Ok, I'm sorry for my mistake. I forgot about it. Anyway here's my
program and there seems to be some problem :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>

int main(void)
{
size_t a; /* size_t variable */
char a_str[50]; /* String to be converted */
char *ptr = NULL;
char *endptr;
unsigned long l;

if (fgets(a_str, 50, stdin) == NULL)
{
fprintf(stderr, "Error while entering the stirng\n");
return (1);
}

if ((ptr = strchr(a_str, '\n')) != NULL)
{
*ptr = '\0';
}

errno = 0;

l = strtoul(a_str, &endptr, 0); /* Convert string to long unsigned
first */

if (errno == ERANGE)
{
if (abs(l) == HUGE_VAL)
{
fprintf(stderr, "OVERFLOW\n");
return (1);
}
else
if (l == 0)
{
fprintf(stderr, "UNDERFLOW\n");
return (1);
}
}
else
{
if (l == 0.0)
{
fprintf(stderr, "Conversion failed\n");
return (1);
}
}

if (l <= UINT_MAX) /* On my TCC, size_t is typedefed as unsigned
int */
{
a = (size_t)l;
printf("\n%u", a);
}
else
printf("OVERFLOW");

return (0);
}


The program gives proper output until you enter a negative number for
which, ideally, it should print "UNDERFLOW" but it seems to print
"Conversion failed".
 
P

pereges

Ok, I'm sorry for my mistake. I forgot about it. Anyway here's my
program and there seems to be some problem :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>

int main(void)
{
size_t a; /* size_t variable */
char a_str[50]; /* String to be converted */
char *ptr = NULL;
char *endptr;
unsigned long l;

if (fgets(a_str, 50, stdin) == NULL)
{
fprintf(stderr, "Error while entering the stirng\n");
return (1);
}

if ((ptr = strchr(a_str, '\n')) != NULL)
{
*ptr = '\0';
}

errno = 0;

l = strtoul(a_str, &endptr, 0); /* Convert string to long unsigned
first */

if (errno == ERANGE)
{
if (abs(l) == HUGE_VAL)
{
fprintf(stderr, "OVERFLOW\n");
return (1);
}
else
if (l == 0)
{
fprintf(stderr, "UNDERFLOW\n");
return (1);
}
}
else
{
if (l == 0.0)
{
fprintf(stderr, "Conversion failed\n");
return (1);
}
}

if (l <= UINT_MAX) /* On my TCC, size_t is typedefed as unsigned
int */
{
a = (size_t)l;
printf("\n%lu", (unsigned long)a);
}
else
printf("OVERFLOW");

return (0);

}

The program gives proper output until you enter a negative number for
which, ideally, it should print "UNDERFLOW" but it seems to print
"Conversion failed".
 
V

vippstar

Ok, I'm sorry for my mistake. I forgot about it. Anyway here's my
program and there seems to be some problem :
if (fgets(a_str, 50, stdin) == NULL)
{
fprintf(stderr, "Error while entering the stirng\n");
return (1);
return EXIT_FAILURE.
l = strtoul(a_str, &endptr, 0); /* Convert string to long unsigned
first */
The program gives proper output until you enter a negative number for
which, ideally, it should print "UNDERFLOW" but it seems to print
"Conversion failed".
strtoul() converts a string to unsigned long.
unsigned integers CANNOT have negative values.
See all my previous posts telling you this exact thing!
 
P

pereges

strtoul() converts a string to unsigned long.
unsigned integers CANNOT have negative values.
See all my previous posts telling you this exact thing!

Then how to detect unsigned integer underflow ?? or its not possible
with strtoul and it will simply report as "conversion failed"
 
B

Ben Bacarisse

pereges said:
Then how to detect unsigned integer underflow ?? or its not possible
with strtoul and it will simply report as "conversion failed"

The point is that an input of "-36" is as meaningless as one of
"banana" when passed to strtoul. If you want, for some odd reason, to
accept a negative number and then check that it is positive you need
to use strtol, assign the result to a signed long, and compare that.
Seem like a waste of time, but you can do that it you like.
 
S

santosh

pereges said:
Then how to detect unsigned integer underflow ?? or its not possible
with strtoul and it will simply report as "conversion failed"

Unsigned types don't underflow or overflow in C. Rather they "wrap
around". If you attempt to store a negative integer in an unsigned
object, what will actually be stored is a positive value determined
according to the properties of modular arithmetic.

<http://en.wikipedia.org/wiki/Modular_arithmetic>

So unsigned integers cannot, by definition, hold "wrong" values. If you
want, you can, in your program, check the numeric strings you operate
upon for the presence of a '-' prefix before attempting to convert them
to unsigned integers.
 
P

pereges

The point is that an input of "-36" is as meaningless as one of
"banana" when passed to strtoul. If you want, for some odd reason, to
accept a negative number and then check that it is positive you need
to use strtol, assign the result to a signed long, and compare that.
Seem like a waste of time, but you can do that it you like.

No, I guess that would over complicate things. I'm only interested in
taking a input from the user and checking if it is within the range of
representable values for a particular data type. I realized scanf is
somewhat dangerous in that regard.
 
P

pereges

Unsigned types don't underflow or overflow in C. Rather they "wrap
around". If you attempt to store a negative integer in an unsigned
object, what will actually be stored is a positive value determined
according to the properties of modular arithmetic.

<http://en.wikipedia.org/wiki/Modular_arithmetic>

So unsigned integers cannot, by definition, hold "wrong" values. If you
want, you can, in your program, check the numeric strings you operate
upon for the presence of a '-' prefix before attempting to convert them
to unsigned integers.

Yeah, I noticed that -1 becomes 65535(UINT_MAX). In that case I will
modify my program to :

l = strtoul(a_str, &endptr, 0); /* Convert string to long unsigned
first */

if (errno == ERANGE)
{
if (abs(l) == HUGE_VAL)
{
fprintf(stderr, "OUT OF RANGE OF REPRESENTABLE VALUES\n");
return (1);
}
}
else
{
if (l == 0)
{
fprintf(stderr, "CONVERSION OF STRING FAILED\n");
}
}
 
K

Keith Thompson

pereges said:
After conversion, if I check a against SIZE_MAX and SIZE_MIN..probably
that can help.

As has already been pointed out, there is no SIZE_MIN; it's just 0.

I think that SIZE_MAX is new in C99. If so, you can use (size_t)-1,
which is guaranteed to be the largest value of type size_t.

In C90, size_t can't be any bigger than unsigned long, though it may
be smaller. You can use strtoul() to get an unsigned long value,
compare the result against SIZE_MAX, and assign it to a size_t object.
(Note: no cast is needed or recommended for this assignment.)

In C99, size_t can be bigger than unsigned long; it can even, in
theory, be bigger than unsigned long long. To be completely safe, you
can use strtoumax(). And for compatibility with both C90 and C99, you
can check the value of __STDC_VERSION__, writing separate code for C90
and C99.

It's likely that you don't need absolute 100% portability, and that
restricting yourself to values within the range of unsigned long is
good enough for your purposes; if so, you can write straight
C90-compatible code, at some small risk of rejecting valid size_t
values greater than 2**31-1 (more precisely, greater than ULONG_MAX).
In fact, the C99 standard recommends (but does not insist) that size_t
be no wider than unsigned long.
 
B

Ben Bacarisse

pereges said:
Yeah, I noticed that -1 becomes 65535(UINT_MAX). In that case I will
modify my program to :

l = strtoul(a_str, &endptr, 0); /* Convert string to long unsigned
first */

if (errno == ERANGE)
{
if (abs(l) == HUGE_VAL)
{
fprintf(stderr, "OUT OF RANGE OF REPRESENTABLE VALUES\n");
return (1);
}
}

strtoul does not generate HUGE_VAL (that is a double value). Also
this logic looks odd..
 
P

pereges

strtoul does not generate HUGE_VAL (that is a double value). Also
this logic looks odd..
ok

Yes it does look odd because that would mean conversion of strings
like "0" would also fail. But this what I found on one reference site
about strtoul :

"
On success, the function returns the converted integral number as a
long int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values,
ULONG_MAX is returned, an the global variable errno is set to ERANGE"

Note the bit where it says "If no valid conversion could be performed
0 is returned. And yeah, instead of HUGE_VAL it should be ULONG_MAX
 
P

pereges

btw i want to read a string containing 3 numbers:

"1234 3333 6666"

SO the logic I used was


unsigned long l1, l2, l3;
char s[] = "1234 3333 6666"
char *endptr1, *endptr2

errno = 0;

l1 = strtoul(s, &endptr1, 10);
l2 = strtoul(&endptr1, &endptr2, 10);
l3 = strtoul(&endptr2, NULL, ), 10);

if (errno == ERANGE)
{
if (l1 == ULONG_MAX || l2 == ULONG_MAX || l3 == ULONG_MAX)
{
/* do the error handling */
}
}
else
{
if (s == endptr1 || endptr1 == endptr2)
{
printf("Conversion failed");
return (1);
}
}
 
B

Ben Bacarisse

pereges said:
Yes it does look odd because that would mean conversion of strings
like "0" would also fail.

Exactly, though i was also talking about the if part as well. You
had (corrected to avoid HUGE_VAL)

if (errno == ERANGE) {
if (l == ULONG_MAX)
fprintf(...);
}

I'll say what I'd do below...
But this what I found on one reference site
about strtoul :

"
On success, the function returns the converted integral number as a
long int value.
If no valid conversion could be performed, a zero value is returned.
If the correct value is out of the range of representable values,
ULONG_MAX is returned, an the global variable errno is set to ERANGE"

Note the bit where it says "If no valid conversion could be performed
0 is returned. And yeah, instead of HUGE_VAL it should be ULONG_MAX

And it is correct, but that does not mean that a return of zero means
no conversion could be performed (it's and "if" not an "if and only
if").

I think you are making this too complex. Only two things can go wrong
with strtoul and they are easy to test for. If no conversion has been
done, then the end pointer is set to the initial pointer passed. If a
range error occurs, errno is set and ULONG_MAX is returned:

unsigned long l;
char *ep;
errno = 0;
if ((l = strtoul(num, &ep, 10)) == ULONG_MAX && errno == ERANGE)
fprintf(stderr, "Number out of range.\n");
else if (ep == num)
fprintf(stderr, "Invalid number (not converted).\n");
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,783
Latest member
RickeyDort

Latest Threads

Top