All of the integer types are different, i.e. you can safely overload functions for all of them and you won't get any conflict. However, some times use the same number of bits for their representation. Even if they use the same number of bits signed and unsigned types always have a different range. Except for char
, using any integer type without signed
is equivalent to using it with signed
, i.e. signed int
and int
are equivalent. char
is a different type as signed char
and unsigned char
but char
has the same representation and range of either signed char
or unsigned char
. You can use std::numeric_limits<char>::is_signed
to find out which it uses.
On to the more interesting aspects. The following conditions are all true:
7 <= std::numeric_limits<signed char>::digits
sizeof(char) == 1
sizeof(char) == sizeof(signed char)
sizeof(char) == sizeof(unsigned char)
15 <= std::numeric_limits<short>::digits
sizeof(char) <= sizeof(short)
sizeof(short) <= sizeof(int)
31 <= std::numeric_limits<long>::digits
sizeof(int) <= sizeof(long)
63 <= std::numeric_limits<long long>::digits
sizeof(long) <= sizeof(long long)
sizeof(X) == sizeof(signed X)
sizeof(signed X) == sizeof(unsigned X)
(where "X" is one of char
, short
, int
, long
, and long long
).
This means that the size of all integer types can be the same as long as this types hold at least 64 bits (and apparently the Cray X-MP was such a beast). On contemporary machines typically sizeof(int) == sizeof(long)
but there are machines where sizeof(int) == sizeof(short)
. Whether long
is 32 or 64 bits depends on the actual architecture and both kinds are currently around.