csigned-integer

Largest positive value of a signed integer type of unknown size


If we have a unsigned integer type which we may not know the size of, for example size_t, then we can get the largest value it can hold relatively simply with something like:

size_t maximal = -1;

Is there a similar technique for a signed integer type, such as ssize_t? As in:

ssize_t smaximal = ???;

Note, there may not be a corresponding unsigned type, for example time_t (ignoring for the moment it might not even be integral).

[EDIT 1] The use of size_t/ssize_t/time_t are just for illustration purposes, I am looking for a general solution where there is no XXX_MAX help.

[EDIT 2] This appears to work, but I am unsure if this is "just luck":

#include "foo_library_with_no_max_macros_because_they_are_dumb.h"

foo_int_type foo = (((unsigned)-1) >> 1);

(where the actual type of foo_int_type gets determined through some horrid pre-processor goop I do not wish to replicate)


Solution

  • If you don't know the size of the type and don't have library support to determine the maximum value, you can resort to exploiting the binary representation.

    The usual way to represent signed integers is using the Two's complement. The maximum value of a signed type in two's complement is a zero followed by ones (011111...111).

    Now how to obtain that value? We need to start with a known value and use bitwise operations to obtain the desired result. Known values:

    don't really help. But

    gets us rather close. Now we don't know the constant FOO_MIN == 1000...000 which we could use to XOR() with -1, so we can resort to bit shifting. If we shift -1 right by one bit and ensure that 0 will be shifted in, we will get the desired value.

    In C, right bit shifting of negative values is implementation-defined, so it can be both arithmetical (which shifts in 1) and logical (which shifts in 0) shift, and mostly it is arithmetical (see this answer), so we will need to type-cast the value to a large enough unsigned type before the shift.

    Here goes:

    #include <stdint.h>
    #include "foo_library_with_no_max_macros_because_they_are_dumb.h"
    
    foo_int_type foo = ((uint64_t)((foo_int_type)-1)) >> 1;
    

    Alternatively, we can use sizeof() to produce FOO_MIN.

    #include "foo_library_with_no_max_macros_because_they_are_dumb.h"
    
    foo_int_type foo_min = ((foo_int_type)1) << (8 * sizeof(foo_min) - 1);
    foo_int_type foo = ((foo_int_type)-1) ^ foo_min;