Reputation: 2052
#include <stdio.h>
int main(int argc, char* argv[]) {
unsigned char c = 10;
unsigned short d = 10;
unsigned int e = 10;
unsigned long f = 10;
double g = -c;
double h = -d;
double i = -e;
double j = -f;
printf("%d %lf\n", c, g);
printf("%u %lf\n", d, h);
printf("%u %lf\n", e, i);
printf("%lu %lf\n", f, j);
}
gives as output
10 -10.000000
10 -10.000000
10 4294967286.000000
10 18446744073709551616.000000
Why are the results inconsistent, yielding -10 for some types and huge values for others?
Upvotes: 5
Views: 553
Reputation: 263177
The operand of a unary -
operator is promoted; types narrower than int
are promoted to int
or to unsigned int
.
Since (signed) int
can hold all the values that can be represented by an unsigned char
, the value (unsigned char)10
is promoted to the signed int
value 10
. Negating that gives you the (signed) int
value -10
, which is then converted to double
.
An unsigned int
is not "promoted" to int
, because int
can't hold all the values. So the expression -e
applies the unsigned int
negation operator, which obviously cannot yield a negative value. The result is UINT_MAX + 1 - 10
, which on your system is 4294967286
. Converting to double
yields the value you see.
Likewise, unsigned long
is not promoted, so -f
yields ULONG_MAX + 1 - 10
, which when converted to double
yields 18446744073709551606
(264-10) (apparently your system has 64-bit long
and unsigned long
). Converting that value to double
loses some precision, yielding the value you see.
Aside from the promotion rules, it's important to remember that the type of a C expression is (almost always) not affected by the context in which it appears. -f
yields a result of the same value and type regardless of what it's assigned to.
Upvotes: 13