In C or C++ it is said that the maximum number a size_t (an unsigned int data type) can hold is the same as casting -1 to that data type. for example see Invalid Value for size_t
Why?
I mean, (talking about 32 bit ints) AFAIK the most significant bit holds the sign in a signed data type (that is, bit 0x80000000 to form a negative number). then, 1 is 0x00000001.. 0x7FFFFFFFF is the greatest positive number a int data type can hold.
Then, AFAIK the binary representation of -1 int should be 0x80000001 (perhaps I'm wrong). why/how this binary value is converted to anything completely different (0xFFFFFFFF) when casting ints to unsigned?? or.. how is it possible to form a binary -1 out of 0xFFFFFFFF?
I have no doubt that in C: ((unsigned int)-1) == 0xFFFFFFFF or ((int)0xFFFFFFFF) == -1 is equally true than 1 + 1 == 2, I'm just wondering why.
For example, in 32-bit mode, the hexadecimal value 0xFFFFFFFF is equivalent to the decimal value of "-1". In 64-bit mode, however, the decimal equivalent is 4294967295. To obtain the value "-1" the hexadecimal constant 0xFFFF_FFFF_FFFF_FFFF (or the octal equivalent), or the decimal value -1, should be used.
Unsigned Integers (often called "uints") are just like integers (whole numbers) but have the property that they don't have a + or - sign associated with them. Thus they are always non-negative (zero or positive). We use uint's when we know the value we are counting will always be non-negative.
That's right, the range of unsigned int is 65535. so when increment by 1 it doesn't go -65534 ( because unsigned int can't accept negative numbers accept only positive numbers) hence it goes to first positive number 0. Then it is further incremented in printf so it shows 1.
uint32_t (or however pre-C++11 compilers call it) is guaranteed to be a 32-bit unsigned integer; unsigned int is whatever unsigned integer the compiler likes best to call unsigned int , as far as it meets the requirements of the standard (which demands for it a 0-65535 minimum range).
C and C++ can run on many different architectures, and machine types. Consequently, they can have different representations of numbers: Two's complement, and Ones' complement being the most common. In general you should not rely on a particular representation in your program.
For unsigned integer types (size_t
being one of those), the C standard (and the C++ standard too, I think) specifies precise overflow rules. In short, if SIZE_MAX
is the maximum value of the type size_t
, then the expression
(size_t) (SIZE_MAX + 1)
is guaranteed to be 0
, and therefore, you can be sure that (size_t) -1
is equal to SIZE_MAX
. The same holds true for other unsigned types.
Note that the above holds true:
Also, the above means that you can't rely on specific representations for signed types.
Edit: In order to answer some of the comments:
Let's say we have a code snippet like:
int i = -1; long j = i;
There is a type conversion in the assignment to j
. Assuming that int
and long
have different sizes (most [all?] 64-bit systems), the bit-patterns at memory locations for i
and j
are going to be different, because they have different sizes. The compiler makes sure that the values of i
and j
are -1
.
Similarly, when we do:
size_t s = (size_t) -1
There is a type conversion going on. The -1
is of type int
. It has a bit-pattern, but that is irrelevant for this example because when the conversion to size_t
takes place due to the cast, the compiler will translate the value according to the rules for the type (size_t
in this case). Thus, even if int
and size_t
have different sizes, the standard guarantees that the value stored in s
above will be the maximum value that size_t
can take.
If we do:
long j = LONG_MAX; int i = j;
If LONG_MAX
is greater than INT_MAX
, then the value in i
is implementation-defined (C89, section 3.2.1.2).
It's called two's complement. To make a negative number, invert all the bits then add 1. So to convert 1 to -1, invert it to 0xFFFFFFFE, then add 1 to make 0xFFFFFFFF.
As to why it's done this way, Wikipedia says:
The two's-complement system has the advantage of not requiring that the addition and subtraction circuitry examine the signs of the operands to determine whether to add or subtract. This property makes the system both simpler to implement and capable of easily handling higher precision arithmetic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With