Consider the following code:
template class StaticAssert;
template<> class StaticAssert {};
StaticAssert< (-1 < sizeof(in
The following is how standard (ISO 14882) explains abort -1 > sizeof(int)
Relational operator `>' is defined in 5.9 (expr.rel/2)
The usual arithmetic conversions are performed on operands of arithmetic or enumeration type. ...
The usual arithmetic conversions is defined in 5 (expr/9)
... The pattern is called the usual arithmetic conversions, which are defined as following:
The integral promotions is defined in 4.5 (conv.prom/1)
An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; otherwise, the source rvalue can be converted to an rvalue of type unsigned int.
The result of sizeof is defined in 5.3.3 (expr.sizeof/6)
The result is a constant of type size_t
size_t is defined in C standard (ISO 9899), which is unsigned integer type.
So for -1 > sizeof(int)
, the > triggers usual arithmetic conversions. The usual arithmetic conversion converts -1 to unsigned int because int cannot represent all the value of size_t
. -1
becomes a very large number depend on platform. So -1 > sizeof(int)
is true
.
Because unsigned is stronger then signed and -1 converted to unsigned value as of size_t
, so actually -1 == 0xFFFFFFFF > 4
This is how it should work according to C++ standard
It's simple and sad. In C/C++:
1U < 2U
(IOW 0U
is the smallest unsigned
value)sizeof
has type size_t
size_t
is an unsigned integer type -1 < 1U
is interpreted as unsigned(-1) < 1U
, and unsigned(-1)
= - 1U
, and obviously - 1U < 1U
, so -1 < 1U
is true.sizeof something
acts (mostly) as an equivalent class (!!!).-1 < sizeof something
The conclusion: this is a design error inherited from C.
Rule:
Only use unsigned types for modular arithmetic, bits manipulations (&
, |
, ^
, <<
, >>
, ~
operators), byte manipulations (unsigned char
means "byte" in C/C++), and characters (unsigned char
means character in C/C++).
Do not use unsigned types to do arithmetic.
If a function expects an integer value that should never be negative, take a signed integer, and optionally check in the function that the value is in range.
because -1 gets casted to size_t
and this is an unsigned data type - so (size_t)-1 == 4294967295
(on a 32bit system) which is definitely larger than 4
if you add -Wall
to the gcc settings for example you get a warning that you are comparing a signed and an unsigned data type