Question

By SuSv3, ssize_t is required to be a signed integer type. If I want to check if a value I calculate is larger than the maximal value allowed for such a data type, I could compare it to INT_MAX, which isn't nice.

Is there a more portable way this comparison can be done - a macro/function f that works as in

 f(<typedef'ed datatype>) = {maximum value allowed for <TDDT> on this system)?

, or a short sequence of such operations to the same sort?

System:
Ubuntu 12.04.
glibc 2.15
Kernel 3.2.0

P.S.: When googling this, I first thought that the gcc extension 'typeof' sounded promising; but it seemed to not help here (or does it?). This is to say I'm fine with anything that might be a gcc extension/attribute/etc.

Was it helpful?

Solution

For an unsigned arithmetic type, (type)-1 is the maximum value. Since you don't know what the relative size of types is, cast to uintmax_t:

#define UNSIGNED_TYPE_MAX(t) ((uintmax_t)(t)-1)
if ((uintmax_t)x > UNSIGNED_TYPE_MAX(size_t)) puts("too large");

There is no such shortcut for signed types. In fact, I don't think there's any way of determining the largest value of a signed type in strictly portable C89 or C99, without using the corresponding constant, such as SSIZE_MAX for ssize_t. C99 specifies constants for each type designed for arithmetic defined in stdint.h for the types defined in ISO C. For types defined in POSIX but not in standard C, there are many values in limits.h; note that they are the limit of what can be valid values for what the type is intended for, rather than the limit of what can fit in the type. For example, if size_t is a 32-bit type, then SIZE_MAX is guaranteed to be 232-1, whereas SSIZE_MAX could be less than 231-1 if the implementation doesn't support any byte count larger than that.

With the added assumption that integers are represented in binary and there are no padding bits, which is safe if you're limiting yourself to POSIX (where CHAR_BIT is always 8), you can deduce the maximum value by computing the size of the type: there is one sign bit in a signed type, and everything else is a value bit.

#define SIGNED_TYPE_MAX(t) (((uintmax_t)1 << (sizeof(t) * CHAR_BIT - 1)) - 1)

Note that things like “double until it stops growing” or “shove in the bit pattern 0111…111” are dodgy. The C standard says that the behavior is undefined for signed types, and GCC takes advantage of this to perform optimizations on operations on signed types that can result in the wrong value if an overflow happens. For example, it might perform computations in a larger-size register, so that the overflow turns out not to happen.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top