I was doing some experiments in a code in order to prove the theory. this is my code:
#include <stdio.h>
int main(){
unsigned int x,y,z;
if(1){
x=-5;
y=5;
z=x y;
printf("%i",z);
}
return 0;
}
But for what i know the output should have been 10, but instead it prints 0, why this is happening? why i can assign a negative value to an unsigned int data type
Thanks in advance!
..........................
CodePudding user response:
From section 6.5.16.1 of the C standard:
In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
From section 6.3.1.3 Signed and unsigned integers:
... Otherwise, if the new type is unsigned, 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.
So x=-5
assigns MAX_UINT 1 - 5
to x
.
CodePudding user response:
Signed to unsigned conversion happens as per "mathematic modulus by UINT_MAX 1", from C17 6.3.1.3:
Otherwise, if the new type is unsigned, 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
Now as it happens, on 2's complement computers this is the same as taking the binary representation of the signed number and treat it like an unsigned number. In your case -5
is represented as binary 0xFFFFFFFB
, so the unsigned number ends up as 4294967291
. And 4294967291 5
creates an unsigned wrap-around from UINT_MAX = 4294967295
to 0
(which is well-defined, unlike signed overflow).
So -5
does not just discard the sign when converted to unsigned. If that's what you want to happen, use the abs()
function from stdlib.h.
CodePudding user response:
It's a basic characteristic of pretty much all integral types that they have a defined range of values they can hold. But then the question is, what happens if you try to set a value outside that range? For C's unsigned
types, the answer is that they operate via modular arithmetic.
On a modern machine, type unsigned int
probably has a range of 0 to 4294967295. Obviously -5 does not fit into that range. So modular arithmetic says that we add or subtract some multiple of 4294967296 until we get a value that is in the range. Now, -5 4294967296 is 4294967291, and that is in range, so that's the value which gets stored in your variable x
.
So then x y
will be 4294967296, but that's not in the range of 0 to 4294967295, either. But if we subtract 4294967296, we get 0, and that's in range, so that's our answer.
And along the way we've discovered how two's complement arithmetic works. It turns out that, if we had declared x
as a signed
int and set it to -5, it would have ended up containing the same bit pattern as 4294967291. And as we've seen, 4294967291 is precisely the bit pattern we want to be able to add to 5 in order to get 0 (after wrapping around, that is). So 4294967291 is a great internal value to use for -5, since you obviously want -5 5 to be 0.
CodePudding user response:
Why i can assign a negative value to an unsigned int data type?
In trying to report the value, code invokes undefined behavior (UB) using a mismatched printf1()
specifier with unsigned
:
// printf("%i",z); // Bad
printf("%u\n",z); // Good
Try printf("%u %u %u %u\n", x, y, z, UINT_MAX);
to properly see all 4 values.
x=-5;
assigns an out-of-range value to an unsigned
. With unsigned types, the value is converted to an in-range value by adding/subtracting UINT_MAX 1
until in range. In this case x
will have the value of UINT_MAX 1 - 5
.
y=5;
is OK.
x y
will then incur unsigned math overflow. The sum is also converted to an in-range value in a like=wise manner.
x y
will have the value of (UINT_MAX 1 - 5) 5
--> (UINT_MAX 1 - 5) 5 - (UINT_MAX 1)
--> 0.