I don\'t get this one!
#include
int main()
{
unsigned short t1 = 0, t2 = 0;
if( t1 < t2-1 )
printf(\" t1 < t2-1\\n\");
The C language performs the "Usual arithmetic conversions" for many operators - the conversions are outlined in 6.3.1.8 of the C99 standard. For integral operands, first promotions are performed, and this is what's causing your issue. The promotions are outlined in 6.3.1.1 (Arithmetic operands/Boolean, characters,and integers), which says among other things:
If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
The promotions are applied only to objects or expressions with an integer type with a rank less than int
and unsigned int
(or bitfields).
So in your exression:
t1 < t2-1
even though the variables are unsigned short
they are promoted to int, since on your platform int
can represent all the values of unsigned short
. So the expression is evaluated using int
types, and no underflow occurs - the t2-1
part of the expression ends up as negative 1.
In the expression:
s1 < s2-1
the unsigned long
types aren't promoted, because they have a higher 'rank' than int
/unsigned int
, so the expression is evaluated using unsigned arithmetic (with the underflow from the subtraction), and the s2-1
subexpression evaluates to a very large number, not negative 1.
As litb indicated in a comment, if the platform had int
implemented as a 16-bit type (which is permitted - MS-DOS for example), the promotion of unsigned short
would be to unsigned int
instead of int
, since an int
wouldn't be able to represent all values of unsigned short
(unsigned short
must be at least 16-bits). In that case, both if
statements would evaluate to true.
Iam not sure but I suspect that the expression t2-1 automatically widened into an int value. I do not have the c standard here what the exact conversion rules are, but I believe types smaller than int are automatically widened.
-1 is represented as all 1s. Therefore when interpreted as unsigned, its value is 2^32-1, which is clearly greater than 0. I'd guess that the first comparison is getting expanded to perform 32-bit signed arithmetic (perhaps due to the "1" being a signed int).
Note that the following WILL get to the printf, because the comparison is now done in 16-bit unsigned space again:
u32 temp = t2 - 1;
if( t1 < temp )
printf(" t1 < t2-1\n");
C coercions, as you're discovering, are not always obvious, whenever you operate between different types. t2
is u16, 1
is int
(presumably 32-bits), so t2-1
is exactly such an "operation between different types" and results in an overall coercion to int (as it's "longer" than u16...). Later, as s2 and 1 are both 32-bits (though of different signedness), the overall coercion is to unsigned long. So, the sizes of the types involved do help determine the signedness of the overall coercion.
I suggest avoiding mixed-signedness (and ideally also mixed-size!) operations (via casting or special literal notation for literals such as 1
that otherwise will have int
type and make your life potentially complicated and your code potentially unportable;-).