Reputation: 53112
So, if you ever try evaluating an unsigned integer < 0, you get a warning that says:
comparison of unsigned expression < 0 always false
This is because unsigned integers are never technically negative, here's the best explanation I've found so far: here
But if I run something like this:
for (int i = 0; i < 10; i++) {
testInt--;
NSLog(@"TestInt = %li", testInt);
// WARNING AREA //
if (testInt < 0) {
NSLog(@"HI");
}
// OK //
if (testInt == -1) {
NSLog(@"Negative ...");
}
}
I'll get output:
TestInt = 4
TestInt = 3
TestInt = 2
TestInt = 1
TestInt = 0
TestInt = -1
Negative ...
TestInt = -2
TestInt = -3
TestInt = -4
TestInt = -5
You can see that the number evaluates fine for negative values, and can equal -1.
After @RobP's answer, I noticed a problem with my logging, it should be %lu
which gives the output:
TestInt = 4
TestInt = 3
TestInt = 2
TestInt = 1
TestInt = 0
TestInt = 18446744073709551615
Negative ...
TestInt = 18446744073709551614
TestInt = 18446744073709551613
TestInt = 18446744073709551612
TestInt = 18446744073709551611
However, my question still stands because it can still evaulate numb == -1
and not numb < 0
:
Why can a NSUInteger be simultaneously equal to -1 but not less than 0?
Upvotes: 1
Views: 3265
Reputation: 2992
Technically your number is never equal to -1
. When you compare your unsigned number to a signed -1
, the last is converted to an unsigned as well, hence yielding a value that is equal to testInt
.
The comparison of an unsigned
versus a 0
and mainly using the less operator is still always false, because 0
is an unsigned, hence no promotion from one data type to another doesn't takes place.
Upvotes: 0
Reputation: 141554
There's no "technically" about it. Unsigned integers are never negative, full stop. They either hold 0
or a positive value. This doesn't need any further explanation.
They don't "remember" if they were originally assigned from a signed value, or anything like that.
As you discovered, your original code caused undefined behaviour by using the wrong format specifier for printf
. All that tells you is (at best) that the bits used to store this unsigned int are the same bits that would be used to store a particular signed int. But the meaning of the bits is different, that's what data types do: they tell how a certain set of bits should be interpreted as a value.
In the code numb == -1
, there is a problem. You are using ==
on two different data types. In Java for example, the compiler rejects this outright. However, in C and C++ there are some rules called implicit conversions that will guess what you were most likely trying to do, and perform a conversion on one of the operands to match the other one.
In this particular case, the rule is that if one operand has type signed T
and the other unsigned T
, then the signed one is convered to unsigned. So your code actually behaves like:
numb == (unsigned long)-1
(assuming numb
is unsigned long
). Further, part of the definition of unsigned long
is that when you assign to it an out-of-range value, that value is adjusted modulo ULONG_MAX + 1
until it comes in range. So the code is also equivalent to:
numb == ULONG_MAX
This is why the first output you see after 0
is ULONG_MAX
.
Upvotes: 1
Reputation: 9522
The problem lies in your display of the numbers, not the numbers. This line:
NSLog(@"TestInt = %li", testInt);
takes your unsigned integer and displays it as if it's a signed int. Change the format specifier to %lu and you should see what your values "really" are to the machine.
EDIT: Thanks to Massa for comment below about the equality of the comparison. When you compare your unsigned variable to the signed value -1, the -1 gets changed into an unsigned value (normally max value of an unsigned int) and they are equal, just as when you take an unsigned int equal to 0 and subtract 1, it becomes UINT_MAX.
Upvotes: 2