-3
#include<stdio.h>
void main()
{
    unsigned int a;
    printf("Enter a number:");
    scanf("%u",&a);
    if ( a <= 4294967295) {
        printf("Entered no is within limit\n");
    } 
    else {
        printf("Entered no is not in the limit");
    }
}

Which input number will execute the else block with the above condition?

The if block is always executed though input is greater than the limit. It is because of wrapping. Is there is any way to find out wrapping?

This is because maximum limit of unsigned int is 4294967295 and it is 32 bits of 1 in binary if my input is 4294967296 it becomes 1 followed by 32 bits of 0. we can't access that 33rd bit of 1 Is there is any possibility to access that 33rd bit?

pradeep
  • 1
  • 3
  • 3
    Given that you have 32 bit integers, the condition will always be true. And that's it. – Lundin Jul 01 '16 at 06:47
  • As mentioned you would most probably need 64-bit integers, the availability of these may depend on which architecture you're using. Which architecture are you using? Or at least tell us what `sizeof(long)` and `sizeof(long long)` gcc reports. If it's `4` then you're out of luck (or at least the problem is becoming much harder), if one of them are larger than `4` then you can use that instead of `unsigned`. – skyking Jul 01 '16 at 06:52
  • Use a long long variable instead of unsigned int. Format for `scanf` will be "%ld" or "%"PRId64 – LPs Jul 01 '16 at 06:56
  • maximum limit of unsigned it is 4294967295.....and it is 32 bits of 1 in binary............if input is 4294967296....it becomes 1 followed by 32 bits of 0.....we can't access that 33rd bit 1....is there is any possibility to access that 33rd bit? – pradeep Jul 01 '16 at 07:05
  • 2
    @pradeep - yes. Use a variable that has more than 32 bits, as has already been said. – enhzflep Jul 01 '16 at 07:15
  • Actually I'm not sure if passing the number 4294967296 to this scanf call is well-defined behavior. – Lundin Jul 01 '16 at 07:41
  • 1
    You should actually have received a "Condition is always true" warning from your compiler. – tofro Jul 01 '16 at 09:30

2 Answers2

3

Which input number will execute the else block with the above condition?

Most likely your system uses 32 bit unsigned int with maximum value 4294967295.

If so, there is no input that can trigger the else block.

As commented by many, the simple solution is to use a variable with more bits (if possible). But as pointed out by @Brendan it just give you other problems.

A more robust solution is to write your own function to parse the input instead of using scanf

Such a function could be something like this:

#include <stdio.h>
#include <limits.h>

// Returns 1 if the string can by converted to unsigned int without overflow
// else return 0
int string2unsigned(const char* s, unsigned int* u)
{
    unsigned int t = 0;
    if (*s > '9' || *s < '0') return 0;      // Check for unexpected char
    while(*s)
    {
        if (*s == '\n') break;                   // Stop if '\n' is found 
        if (*s > '9' || *s < '0') return 0;      // Check for unexpected char
        if (t > UINT_MAX/10) return 0;           // Check for overflow
        t = 10 * t;
        if (t > UINT_MAX - (*s - '0')) return 0; // Check for overflow
        t = t + (*s - '0');
        s++;
    }
    *u = t;
    return 1;
}

int main(void) {
    unsigned int u;
    char s[100];
    if (!fgets(s, 100, stdin))   // Use fgets to read a line
    {
        printf("Failed to read input\n");
    }
    else
    {
        if (string2unsigned(s, &u))
        {
            printf("OK %u\n", u);
        }
        else
        {
            printf("Illegal %s", s);
        }
    }
    return 0;
}

Example:

input: 4294967295
output: OK 4294967295

 input: 4294967296
 output: Illegal 4294967296

(Thanks to @chux for suggesting a better alternative to my original code)

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
2

Using a larger integer type (with more bits) is wrong and broken. All that will do is give you a new problem (e.g. accepting numbers above 18446744073709551615 when it shouldn't).

For user interface design; a single "Entered number is not within the limit" error message is unacceptable. You have to tell the user what the real problem is and also remind the user of what you are expecting.

At a minimum, there are at least 4 different kinds of errors you should handle (and therefore at least 4 different error messages you should be able to display):

  • No input received (stdin gave you an EOF)

  • Input contained something that isn't a valid character (e.g. the byte 0x00, malformed UTF-8 multi-byte sequences, ASCII characters above 0x7F, etc)

  • Input contained an unrecognised/unaccepted character (e.g. the user typed "Bork!", or "0x1234", or "twelve"; or the user typed "12,345.00" and your code can't handle thousand's separators or fractions)

  • Input is a valid number but is not within a certain range. This might include negative values like "-1234" (and in that case the minus sign should not be treated as unrecognised/unaccepted character causing the wrong error message to be given).

Also note that the limit does not depend on the size of the variable type you use; the size of the variable type you choose depends on the limit. For example, if you're asking someone to enter their age and they type "12345" then that should cause an error message like "Number out of range (age must be between 1 and 150)." regardless of whether it causes an overflow or not. In this case the limit would be 150 (and not something like INT_MAX because nobody is ever likely to be that old). Because the limit is 150, you can't choose to use signed char as your variable type but could choose to use uint8_t (or anything larger).

With all of this in mind; scanf() is never usable for parsing "strings from humans". You must write your own parser or find something (a "non-standard" library) that is suitable.

Brendan
  • 35,656
  • 2
  • 39
  • 66