The process of changing a value from one type to another is called casting. Unsigned integers cast differently than signed integers, and can result in the sign being lost, and numerical comparisons acting in unexpected ways. For a program to be correct, the type of every variable must be understood.
The type of an integer variable determine the result of numerical comparisons. For instance,
unsigned int u ; assert(u>-1) ;is always false, regardless of the value of u. Whereas:
short s ; assert( ((long)(unsigned short) s)>-1) ;is always true regardless of the value of s (although technically it is considered undefined for negative values of s).
Whenever possible, the mathematical value of an integer variable should be preserved by the cast. This is not possible in several cases.
When casting from long to int, int to short, or short to byte, it might not be possible to preserve the value — the smaller storage location does not have the range to contain all values possible in the larger storage location. Typically, C discards the high order bits.
For values of small enough absolute value, there is no change of value — for positive values what gets thrown away are leading zeros, and for negative values what gets thrown away are leading ones. Otherwise, the value will change, and positive values might become negative, and negative values might become positive.
Casting from unsigned to signed, even from long to long, int to int, short to short, or char to char, it might not be possible to preserve the values — unsigned have extended range to represent positive integers. Typically, C does not change the representation under any circumstance. Positive numbers in range of the signed representation retain there value, but large postive numbers will cast to large negative numbers.
Casting a negative number to an unsigned integer cannot possibly preserve the mathematical value. Negative numbers will cast to large positive numbers.
When casting both size and sign, the size is cast first and the sign next.
This rule will sign extend -1 even when casting to unsigned, in which case
the result is a value as large as any positive number, rather than smaller than
all positive numbers. This explains the u>-1
example code, above.
For two's complement representations, these rules constitues choosing an in-range representative for the old value, mod the new size constraint. In this sense, C always preserves value — just not the value expected when integers are understood to have infinite range.