tags:

views:

288

answers:

4

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)?

+11  A: 

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

std::numeric_limits<size_t>::max()
Aleksei Potov
The only downside of this is that the value is not a constant expression. You can do `integral_constant<size_t, (size_t)-1>`, but `integral_constant<size_t, numeric_limits<size_t>::max()>` doesn't work :(
Johannes Schaub - litb
+2  A: 

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
+14  A: 

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
For C++, the normative wording is at `4.7/2`.
Johannes Schaub - litb
Thanks! That's exactly the wrinkle I was wondering about.
Pillsy
+4  A: 

"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.

AndreyT
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
I'd agree with "serve the needs of the user" part. But "serve the needs of the hardware"?... No.
AndreyT
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