views:

600

answers:

4

Consider the following code:

template<bool> class StaticAssert;
template<> class StaticAssert<true> {};
StaticAssert< (-1 < sizeof(int)) > xyz1; // Compile error
StaticAssert< (-1 > sizeof(int)) > xyz2; // OK

Why is -1 > sizeof(int) true?

  1. Is it true that -1 is promoted to unsigned(-1) and then unsigned(-1) > sizeof(int).
  2. Is it true that -1 > sizeof(int) is equivalent to -1 > size_t(4) if sizeof(int) is 4. If this is so why -1 > size_t(4) is false?

Is this C++ standard comformant?

+15  A: 

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

Artyom
doesn't compilers issue warnings for such cases ?
kriss
this doesn't explain why -1 < (size_t) 4, sizeof should use return type size_t..
Anders Westrup
@kriss - Different compilers issue different warnings. Also warnings can be supressed via compiler command-line options, and/or by pragmas in the source code; and/or then can be ignored by the programmer.
ChrisW
**Is this C++ standard comformant?**
Alexey Malistov
Only when One's or Two's complement is used (not sure which here).
rubenvb
@Alexey Malistov Yes
Artyom
@rubenvb: Doesn't matter: `unsigned(-1) == UINT_MAX` per the standard, everywhere.
MSalters
@Artyom: `unsigned is stronger then signed`. What is `stronger`? Standard does not define this term.
Alexey Malistov
@msalters: ok, didn't know that, thanks.
rubenvb
+1  A: 

Got confused with signed and unsigned 64-bit numbers, scratch that :(

FredOverflow
It's nothing to do with 64-bit, it only matters which unsigned type `size_t` actually is and which conversion rules for expressions actualy apply. If, as in most implementations, `size_t` is as wide as an `int` (it doesn't need to be wider) then both sides of the expression must be converted to the unsigned type.
Charles Bailey
@Charles: What do you mean it doesn't need to be wider than `int`? It's perfectly feasible that `size_t` is an unsigned 64-bit type on a 64-bit system, because `sizeof(some_really_huge_array)` might easily exceed 4GB on such a system.
FredOverflow
Also, if you are comparing a narrower signed type to a wider unsigned type there are no cases where the signed equivalent of the wider type would be used, both operands would be converted to the wide unsigned type if the wide unsigned type is at least `unsigned int` or to a signed type of even greater size if `int` is actually wider than 64-bits.
Charles Bailey
I mean that if `size_t` is actually `unsigned int` then both operands are converted to `unsigned int` in `-1 > size_t(4)`. Your answer seemed to imply that it matters that `size_t` is strictly wider than `int` for the comparison to return true.
Charles Bailey
@Charles: "there are no cases where the signed equivalent of the wider type would be used" -> you are right, of course, I got confused there.
FredOverflow
+3  A: 

because -1 gets casted to size_t and this is an unsigned datatype - so (size_t)-1 == 4294967295 (on a 32bit system) which is definitly 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 datatype

Nikolaus Gradwohl
+12  A: 

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:

  • If either operand is of type long double, ...
  • Otherwise, if either operand is dobule, ...
  • Otherwise, if either operand is float, ...
  • Otherwise, the integral promotions shall be performed on both operands.
  • ...

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.

czchen
It could just be a typo but `size_t` is _an_ unsigned integer type and it doesn't have to be the case that `int` can't represent all the values of `size_t` (`size_t` might be `unsigned short`), although it obviously can't on the question asker's platform.
Charles Bailey
`(unsigned T)-1` isn't just a large value, it's *the* largest value `unsigned T` can hold.
GMan
@czchen: I'm well aware what the standard allows. :) -1 is always the largest, read the conversion rules. Or this http://stackoverflow.com/questions/809227/is-it-safe-to-use-1-to-set-all-bits-to-true/809341#809341
GMan
@GMan Thank for your help. I misunderstood the description in standard. (Remove wrong comment)
czchen