Reputation: 3052
I'm trying to test equality of signed and unsigned versions of short, int, and long in C. In particular, I have used the following test code:
#include <stdio.h>
int main() {
signed short ss = 0x8000; // 2^15
unsigned short us = 0x8000;
printf("ss = %i, us = %i\n", ss, us);
if (ss == us) { printf("ss == us\n"); }
else { printf("ss != us\n"); }
signed int si = 0x80000000; // 2^31
unsigned int ui = 0x80000000;
printf("si = %i, ui = %i\n", si, ui);
if (si == ui) { printf("si == ui\n"); }
else { printf("si != ui\n"); }
signed long sl = 0x8000000000000000L; // 2^63
unsigned long ul = 0x8000000000000000UL; // 2^63
printf("sl = %li, ul = %lu\n", sl, ul);
if (sl == ul) { printf("si == ui\n"); }
else { printf("sl != ul\n"); }
}
The code outputs the following:
ss = -32768, us = 32768
ss != us
si = -2147483648, ui = -2147483648
si == ui
sl = -9223372036854775808, ul = 9223372036854775808
si == ui
So for shorts they are not equal, but for the other two they are. Is there something wrong with what I am assuming, or is this just a known quirk of C?
Upvotes: 0
Views: 687
Reputation: 41220
It appears that in your compiler, both short
and unsigned short
can be converted to int
without loss of information; their comparison is done after the conversion ("promotion").
The promotions are explained in the section Usual Arithmetic Conversions at securecoding.cert.org
If both operands have the same type, no further conversion is needed.
If both operands are of the same integer type (signed or unsigned), the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.
If the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
Upvotes: 2
Reputation: 145297
Given your output, the short
and unsigned short
are smaller than int
. Both get converted to int
for the first comparison and the converted values differ.
For int
and unsigned int
, the comparison is performed as unsigned int
. The conversion gives the same value and the comparison is true. Note that you should print the numbers with an appropriate format: printf("si = %i, ui = %u\n", si, ui);
For the long
and unsigned long
test, your computer seems to have 64 bit longs, the comparison is performed as unsigned long
, the long
value is converted to an unsigned long
but has the same representation, to comparison is true again.
Note that you should not store numbers larger than the maximum value into a signed type:
signed short ss = 0x8000;
is not guaranteed to store -32768
to ss
.
Same problem for signed int si = 0x80000000;
and signed long sl = 0x8000000000000000L;
.
Upvotes: 0