To test if an string converts to a
unsigned
Use strtoul() to convert to a unsigned long. Yet since that function rolls over negative text to positive integers, use strtol() first.
bool valid_unsigned(const char *s, unsigned *uval) {
char *endptr;
errno = 0;
int base = 0; // Use 10 here if only decimal text acceptable.
long lvalue = strtol(s, &endptr, base);
if (s == endptr) {
*uval = 0;
return false; // No conversion
}
if (lvalue < 0) {
errno = ERANGE; // Perhaps calling code would like to test this.
*uval = 0;
return false; // Negative
}
if ((unsigned long) lvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) lvalue;
return true; // Success
}
#if UINT_MAX > LONG_MAX
// Still could be a value in the LONG_MAX...UINT_MAX range.
errno = 0;
unsigned long uvalue = strtoul(s, &endptr, base);
if (uvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) uvalue;
return true; // Success
}
#endif
errno = ERANGE;
*uval = UINT_MAX;
return false; // Too big.
}
To do: Test trailing text.
Answer from chux on Stack OverflowTo test if an string converts to a
unsigned
Use strtoul() to convert to a unsigned long. Yet since that function rolls over negative text to positive integers, use strtol() first.
bool valid_unsigned(const char *s, unsigned *uval) {
char *endptr;
errno = 0;
int base = 0; // Use 10 here if only decimal text acceptable.
long lvalue = strtol(s, &endptr, base);
if (s == endptr) {
*uval = 0;
return false; // No conversion
}
if (lvalue < 0) {
errno = ERANGE; // Perhaps calling code would like to test this.
*uval = 0;
return false; // Negative
}
if ((unsigned long) lvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) lvalue;
return true; // Success
}
#if UINT_MAX > LONG_MAX
// Still could be a value in the LONG_MAX...UINT_MAX range.
errno = 0;
unsigned long uvalue = strtoul(s, &endptr, base);
if (uvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) uvalue;
return true; // Success
}
#endif
errno = ERANGE;
*uval = UINT_MAX;
return false; // Too big.
}
To do: Test trailing text.
If you are using the function strtoul for converting the string input to an integer, then you don't need to determine yourself whether the input is larger than ULONG_MAX. The function strtoul will report this, by setting the value of errno accordingly. However, depending on the platform, an unsigned long may be able to represent more numbers than an unsigned int. Therefore, after the function strtoul reports that the input range is ok, you should additionally verify that the number is not larger than UINT_MAX.
Another problem with using the function strtoul is that it will accept negative numbers as valid. We must therefore check ourselves whether the first non-whitespace character is a minus sign.
Here is an example program which uses a function get_unsigned_int_from_user which will continue prompting the user for input, until the input is valid and in the range of an unsigned int:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
unsigned int get_unsigned_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p, *q;
unsigned long ul;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//make "p" point to first non-whitespace character
for ( p = buffer; isspace( (unsigned char)*p ); p++ )
;
//since the function "strtoul" accepts negative
//input as valid input, which we don't want, we must
//first check ourselves whether the input starts
//with a minus sign
if ( *p == '-' )
{
printf( "number must not be negative!\n" );
continue;
}
//attempt to convert string to number
errno = 0;
ul = strtoul( p, &q, 10 );
if ( q == p )
{
printf( "error converting string to number\n" );
continue;
}
//make sure that number is representable as an "unsigned int"
if ( errno == ERANGE || ul > UINT_MAX )
{
printf( "number out of range error\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfh4q" gets rejected
for ( ; *q != '\0'; q++ )
{
if ( !isspace( (unsigned char)*q ) )
{
printf( "unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return ul;
continue_outer_loop:
continue;
}
}
int main( void )
{
unsigned int num;
num = get_unsigned_int_from_user( "Please enter a number: " );
printf( "Input is valid, you entered: %u\n", num );
}
This program has the following behavior:
Please enter a number: -1
number must not be negative!
Please enter a number: -5000000000
number must not be negative!
Please enter a number: 5000000000
number out of range error
Please enter a number: 4000000000
Input is valid, you entered: 4000000000
The program behaves this way because UINT_MAX has the value 4294967295 on most common platforms.
The function get_unsigned_int_from_user is a modified version of my function get_int_from_user from this answer of mine. See that answer for further information on how that function works.
Binary basics - why in C is the range of "int" -32768 to 32767 when 2^32 (4 bytes) is 4.294.967.296 different values?
c - What does "-1" represent in the value range for unsigned int and signed int? - Stack Overflow
Range of values in C Int and Long 32 - 64 bits - Stack Overflow
Are these range of values for a 16-bit machine's integers correct?
Videos
To test if an string converts to a
unsigned
Use strtoul() to convert to a unsigned long. Yet since that function rolls over negative text to positive integers, use strtol() first.
bool valid_unsigned(const char *s, unsigned *uval) {
char *endptr;
errno = 0;
int base = 0; // Use 10 here if only decimal text acceptable.
long lvalue = strtol(s, &endptr, base);
if (s == endptr) {
*uval = 0;
return false; // No conversion
}
if (lvalue < 0) {
errno = ERANGE; // Perhaps calling code would like to test this.
*uval = 0;
return false; // Negative
}
if ((unsigned long) lvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) lvalue;
return true; // Success
}
#if UINT_MAX > LONG_MAX
// Still could be a value in the LONG_MAX...UINT_MAX range.
errno = 0;
unsigned long uvalue = strtoul(s, &endptr, base);
if (uvalue <= UINT_MAX && errno == 0) {
*uval = (unsigned) uvalue;
return true; // Success
}
#endif
errno = ERANGE;
*uval = UINT_MAX;
return false; // Too big.
}
To do: Test trailing text.
Answer from chux on Stack OverflowTitle says it all
Consider the values you can achieve with 2 bits:
00 : 0
01 : 1
10 : 2
11 : 3
There are 4 of them, 2 to the power of 2.
But the highest value is not 4, it is 3.
The highest value is 2 to the power of 2 minus 1. I.e. in your representation
2^2-1
or 22-1
Add a bit and you get twice the number, by adding
100 : 4
101 : 5
110 : 6
111 : 7
Total number 8, but highest number 7.
So the "-1" is because always the first of the total of 2n is used for 0,
the 2nd is used for 1, the 3rd is used for 2.
In the end (2n)th one is not available for 2n, it is already used for 2n-1.
n bits can represent 2n different values. (The first bit can have two values * the second bit can have two values * the third bit can have two values * ...)
For example, 3 bits can form 23 = 8 different bit patterns, and thus up to 8 different values.
000
001
010
011
100
101
110
111
If each bit pattern represents an integer, then an n-bit integer can represent 2n different integers. For example,
It could represent the integers from 0 to 2n-1 inclusively
(because (2n-1) - (0) + 1 = 2n different values).For example,
000 0 001 1 010 2 011 3 100 4 101 5 110 6 111 7It could represent the integers from -(2n-1) to 2n-1-1 inclusively
(because (2n-1-1) - (-(2n-1)) + 1 = 2n different values).For example,
100 -4 101 -3 110 -2 111 -1 000 0 001 1 010 2 011 3
You could assign any meaning to these values, but the previously stated ranges are the ones understood by twos'-complement machines for unsigned integers and signed integers respectively.[1]
- On a ones'-complement machine, there are two ways of writing zero (0000...00002 and 1000...00002), so the range is only -(2n-1-1) to 2n-1-1. I think all modern machines are twos'-complement machines, though.
In C and C++ you have these least requirements (i.e actual implementations can have larger magnitudes)
signed char: -2^07+1 to +2^07-1
short: -2^15+1 to +2^15-1
int: -2^15+1 to +2^15-1
long: -2^31+1 to +2^31-1
long long: -2^63+1 to +2^63-1
Now, on particular implementations, you have a variety of bit ranges. The wikipedia article describes this nicely.
No, int in C is not defined to be 32 bits. int and long are not defined to be any specific size at all. The only thing the language guarantees is that sizeof(char)<=sizeof(short)<=sizeof(long).
Theoretically a compiler could make short, char, and long all the same number of bits. I know of some that actually did that for all those types save char.
This is why C now defines types like uint16_t and uint32_t. If you need a specific size, you are supposed to use one of those.
These are the values for 16-bit machine that I got from the C Programming: A Modern Approach, 2nd Edition book by K. N. King.
-
short int: -32,768 to 32,767
-
unsigned short int: 0 to 65,535
-
int: -32,768 to 32,767
-
unsigned int: 0 to 65,535
-
long int: -2,147,483,648 to 2,147,483,647
-
unsigned long int: 0 to 4,294,967,295
Shouldn't a 16-bit machine's unsigned long int range be 0-65,535? Since 1111 1111 1111 1111 is 65,535 I think that the range int he book is wrong. Or am I wrong?
I'm really confused, specially since the range for a 32-bit machine unsigned long int is 0-4,294,967,295 (which is the max value for a 32 bit) and 0-18,446,744,073,709,551,615 the max value for 64 bits. But the book's long int and unsigned long int for a 16-bit machine are the same values for the ones of a 32-bit machine. Way larger than 65,535.
I'm still pretty new at C, so sorry if I'm making a really beginner mistake or I'm not being able to express myself that well.
Thanks.