Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why the result is "2" of unsigned int (1) - unsigned int (0xFFFFFFFF)

Tags:

c

Please look at the following codes:

#include <stdlib.h>
#include <stdio.h>


int main()
{
    unsigned int a = 1;
    unsigned int b = -1;

    printf("0x%X\n", (a-b));

    return 0;
}

The result is 0x2.

I think the integer promotion should not happen because the type of both of "a" and "b" are unsigned int. But the result beats me.... I don't know the reason.

By the way, I know the arithmetic result should be 2 because 1-(-1)=2. But the type of b is unsigned int. When assign the (-1) to b, the value of b is 0xFFFFFFFF actually. It is the maximum value of unsigned int. When one small unsigned value subtract one big value, the result is not that I expect.

From the answer below, I think maybe the overflow is a good explanation。 Now I writes other test codes. It proves the overflow answer is right.

#include <stdlib.h>
#include <stdio.h>

int main()
{
    unsigned int c = 1;
    unsigned int d = -1;


    printf("0x%llx\n", (unsigned long long)c-(unsigned long long)d);

    return 0;
}

The result is "0xffffffff00000002". It is I expect.

like image 663
linuxer Avatar asked Dec 07 '22 18:12

linuxer


2 Answers

unsigned int a = 1;

This initializes a to 1. Actually, since 1 is of type int, there's an implicit int-to-unsigned conversion, but it's a trivial conversion that doesn't change the value or representation).

unsigned int b = -1;

This is more interesting. -1 is of type int, and the initialization implicitly converts it from int to unsigned int. Since the mathematical value -1 cannot be represented as an unsigned int, the conversion is non-trivial. The rule in this case is (quoting section 6.3.1.3 of the C standard):

the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

Of course it doesn't actually have to do it that way, as long as the result is the same. Adding UINT_MAX+1 ("one more than the maximum value that can be represented in the new type") to -1 yields UINT_MAX. (That addition is defined mathematically; it's not itself subject to any type conversions.)

In fact, assigning -1 to an object of any unsigned type is a good way to get the maximum value of that type without having to refer to the *_MAX macros defined in <limits.h>.

So, assuming a typical 32-bit system, we have a == 1 and b == 0xFFFFFFFF.

printf("0x%X\n", (a-b));

The mathematical result of the subtraction is -0xFFFFFFFE, but that's obviously outside the range of unsigned int. The rules for unsigned arithmetic are similar to the rules for unsigned conversion; the result is 2.

like image 100
Keith Thompson Avatar answered Jan 10 '23 18:01

Keith Thompson


Who says you're suffering integer promotion? Let's pretend that your integers are two's complement (likely, though not mandated by the standard) and they're only four bits wide (not possible according to the standard, I'm just using this to simplify things).

int   unsigned-int  bit-pattern
---   ------------  -----------
  1              1         0001
 -1             15         1111
                         ------
  (subtract with borrow) 1 0010
   (only have four bits)   0010  -> 2

You can see here that you can get the result you see without any promotion to signed or wider types.

like image 24
paxdiablo Avatar answered Jan 10 '23 17:01

paxdiablo