tags:

views:

127

answers:

4

I'd like to know the maximum value of size_t on the system my program is running. My first instinct was to use negative 1, like so:

size_t max_size = (size_t)-1;

But I'm guessing there's a better way, or a constant defined somewhere.

+13  A: 

A manifest constant (a macro) exists in C99 and it is called SIZE_MAX. There's no such constant in C89/90.

However, what you have in your original post is a perfectly portable method of finding the maximum value of size_t. It is guaranteed to work with any unsigned type.

AndreyT
+1 Excellent answer.
Stephen Canon
Thank you, my compiler needs the cast, or a warning is issued about change of sign during an integer conversion.
Justicle
Is it true that's perfectly portable? What prevents it from being a trap representation?
jamesdlin
@jamesdlin: The signed-to-unsigned conversion is always well-defined in C. It is required to follow the rules of typical unsigned modulo arithmetics with modulo equal to the largest value of the target unsigned type plus 1. So, in the above case you will get `-1 mod (<max-value> + 1)`, which is always just `<max-value>`.
AndreyT
@jamesdlin: §5.2.4.2.1 guarantees that `-1` is representable as an `int`. §6.3.1.3 guarantees that it converts to a valid `size_t` value.
Stephen Canon
@jamesdlin: another way to see that is that `size_t` is an unsigned type, so all values are valid. This can't be a trap representation since there is no such trap.
Jens Gustedt
@Jens Gustedt: That doesn't help, because I don't think it's necessarily true that all N-bit patterns are necessarily valid for an N-bit unsigned type. However, I do find Stephen's point about §6.3.1.3 compelling since it specifically refers to "the maximal value that can be represented in the new type", which is independent of bit allocation.
jamesdlin
@jamesdlin: yes it does, unsigned types are really simple minded ;-) from "`6.2.6.2 Integer types`": `If there are N value bits, each bit shall represent a differentpower of 2 between 1 and 2^N−1..` So for unsigned integer types there are really no surprises possible.
Jens Gustedt
@Jens Gustedt: You conveniently ignored the part of that section that says: "For unsigned integer types, the bits ... shall be divided into two groups: value bits and padding bits...." Your quote specifically refers to *value bits*.
jamesdlin
@jamesdlin: Yes, but normally you can't create an invalid combination if *padding* bits by doing simple assignment. The danger of producing a trap representation in *padding* bits exists if you "hack" into the object representation through raw memory access, which we are not doing here.
AndreyT
@AndreyT: Yeah, I am now in complete agreement that this won't generate a trap representation. My last couple of comments were solely about the claim that there can be no trap representations for unsigned types.
jamesdlin
A: 

Would something along the lines of (1 << sizeof(size_t)) - 1 work? (Untested, and possibly a language-lawyer reason this won't work...).

Oli Charlesworth
Won't work - `sizeof(size_t)` returns the size in bytes of a `size_t`, not related to the values that go in it. I guess you could do `pow(2, CHAR_BIT*sizeof(size_t)) - 1`, but that seems way too hard.
Carl Norum
The OP wants the maximum value that the `size_t` type can hold. `sizeof` returns the size of the variable in terms of multiples of the `CHAR_BIT` define in `limits.h`. So (assuming 8 bit `char` and 32 bit `size_t`) your solution results in `3`, not `0xFFFFFFFF` as the OP wants.
Praetorian
@Carl: Noooo! The accuracy of `pow` is not guaranteed by any standard, and this *will* generate bogus results on many platforms; even on a platform where `pow` is correctly rounded, if `size_t` is a 64-bit type and `double` corresponds to IEEE double (a common pair of conditions), the rounding of the subtraction will result in the value `2^64` instead of the desired `2^64 - 1`.
Stephen Canon
@Carl and @Praetorian: I've already altered my code to include a left-shift... But agreed, this is too heavyweight.
Oli Charlesworth
Even if you repair this, the one from the OP is much easier and portable.
Jens Gustedt
@Oli: `(1 << sizeof(size_t)) - 1` still doesn't yield the correct answer. If `sizeof(size_t)` is `4`, that expression results in `15`. What you're looking for is `(1 << (CHAR_BIT * sizeof(size_t))) - 1`. But most compilers will complain that your shift value is too large.
Praetorian
@Oli: Sorry to keep correcting you, but there's nothing heavyweight about `(1 << sizeof(size_t)) - 1` either. The `sizeof(size_t)` result is available at compile time, so the compiler will be able to replace that entire expression with a constant value.
Praetorian
@Praetorian: This can't even be repaired in a portable way; shifting by the width of a type (which is presumably intended here, as in your suggested fix) is undefined behavior; even if it were defined, you would have the issue that `1` is an int literal, and `int` might be narrower than `size_t` (very common on 64-bit platforms).
Stephen Canon
@Stephen, yes. It wasn't really intended to be a real solution, just to highlight the fact that @Oli's answer didn't do the right thing.
Carl Norum
@Praetorian: I meant "heavyweight" in terms of ugliness; I'm aware that this will fold down to a constant at compile-time! @everyone: yes, this approach is flawed. Use the OP's idea!
Oli Charlesworth
+2  A: 
#define MAZ_SZ (~(size_t)0)

or SIZE_MAX

nategoose
A: 

The size_t max_size = (size_t)-1; solution suggested by the OP is definitely the best so far, but I did figure out another out another, more convoluted, way to do this. I'm posting it just for academic curiosity.

#include <limits.h>

size_t max_size = ((((size_t)1 << (CHAR_BIT * sizeof(size_t) - 1)) - 1) << 1) + 1;
Praetorian