12

The other day, I came across this construct:

static_cast<size_type>(-1)

in some example C++ code, which is likely (depending on the details of where size_type is from) to be equivalent to the following C:

(size_t)(-1)

As I understand it, it works based on the fact that the representation of -1 in twos complement arithmetic is 11111...1, for as many bits as you have, so this is a quick way of getting the maximum value that an unsigned type like size_t can hold. However, my understanding is also that C doesn't guarantee that twos complement will be used; if the C implementation uses one's complement, this will be 1 less than the the maximum value, and if it's using signed magnitude, it will be just over half the maximum value.

Is there some wrinkle that I'm missing that insures that this works right regardless of the representation of signed integers being used? Does it differ between C and C++ (many surprising things do)?

klutt
  • 30,332
  • 17
  • 55
  • 95
Pillsy
  • 9,781
  • 1
  • 43
  • 70
  • 3
    If you want to be sure, there's always `std::numeric_limits::max()`. – UncleBens Nov 03 '09 at 15:23
  • I think situations like this are why you have static_cast and reinterpret_cast in the language - static_cast can give you something predictable (and thus useful) but which might have a slower implementation on some platforms, whereas reinterpret_cast can do away with any guarantees. – Kylotan Nov 03 '09 at 15:46
  • 4
    This is IMHO the best way to get a number of all one bits. The options using `~0U` work too (and if you forget to add `U` and do `~0` you can end up with all bits 0 for instance) - but using `-1` cast to the `unsigned` type, it always works independent of the type. So you don't have to care about using `ULL` or to cast to `unsigned short` first - you can just use `-1` and assign it :) See also http://stackoverflow.com/questions/809227/is-it-safe-to-use-1-to-set-all-bits-to-true – Johannes Schaub - litb Nov 03 '09 at 15:50

4 Answers4

22

The requirements on unsigned arithmetic guarantee that casting -1 to an unsigned type will produce the largest number possible for the target type. C99, §6.2.5/9: "...a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type."

This is the same in C and C++ (in the C++ standard, similar wording is found in footnote 41 -- it's not normative, but it's explaining other wording that is).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
14

To be on a "safe" side and do it "right" (C++) way, worth looking at STL:

std::numeric_limits<size_t>::max()
Aleksei Potov
  • 1,548
  • 11
  • 14
  • 3
    The only downside of this is that the value is not a constant expression. You can do `integral_constant`, but `integral_constant::max()>` doesn't work :( – Johannes Schaub - litb Nov 05 '09 at 16:21
5

"As I understand it, it works based on the fact that the representation of -1 in twos complement arithmetic is...".

No, it is not based on that fact at all. It is based on the standard requirement, that singed values converted to N-bit unsigned type have to produce an unsigned value, which is "equal" to the original signed one modulo 2^N.

It has to work that way regardless of the signed representation used by the implementation. In case of 2's complement it works that way by itself, but for other representations the compiler will have to do the extra work in order to satisfy the standard requirement.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Uh... to be fair: the standard is written the way it is precisely ti allow for straightforward implementations on CPUs that do 2's complement arithmetic. It's certainly not **incorrect** to invoke 2's complement in an explanation. Language standards exist to serve the needs of the hardware and the user, not the other way around. – Andy Ross Nov 03 '09 at 18:51
  • I'd agree with "serve the needs of the user" part. But "serve the needs of the hardware"?... No. – AnT stands with Russia Nov 03 '09 at 19:22
  • I've downvoted answers before, when i read in them "the value is `UINT_MAX` because in two's complement `-1` is all-bit-one.". They simply had it backwards. Therefor, i'll upvote this answer. – Johannes Schaub - litb Nov 03 '09 at 19:56
3

If you're looking to get the maximum (or minimum) value of a certain type in a portable way, it is best to use the standard numeric_limits class as follows.

#include <limits>

size_type max = std::numeric_limits<size_type>::max()
size_type min = std::numeric_limits<size_type>::min()

I suspect that some implementations of these functions may use the cast you describe as the platform-optimal way to get at the min/max.

Steve Guidi
  • 19,700
  • 9
  • 74
  • 90