The code below defines a macro TYPE_MAX(T) to find the maximum value
of a type T, producing a compile-time constant expression, and
dealing appropriately with possible padding bits. Disclaimers:
1. It relies on implementation-defined behavior for converting
out-of-range values in the case of signed types (mainly
that such conversions produce ordinary values within the
actual range of the type in question).
2. It doesn't work for a signed integer type of one bit (ie,
whose maximum value is 0).
3. It doesn't work for implementations whose largest unsigned
type has more than 16384 value bits.
4. It may produce results that are too low in C90 implementations
for types whose positive ranges exceed those of unsigned long.
Strictly speaking this would make the implementation be non-
conforming if one of those types were, eg, ptrdiff_t, but I
can't rule out the possibility that such implementations
exist. (A similar statement applies to C90 implementations
that define ULLONG_MAX badly; unfortunately it isn't possible
to protect against errant, non-conforming implementations.)
Despite the disclaimers it may be of practical value. I'd be
interested to hear of any failures to produce correct results.
/* File starts here */
#include <limits.h>
#define TYPE_MAX(T) ((T) TM_WT_( T, UNSIGNED_MAX_MAX ))
#if __STDC_VERSION__ > 199900L
#include <stdint.h>
#include <inttypes.h>
#if defined UINTMAX_MAX
#define UNSIGNED_MAX_MAX UINTMAX_MAX
#define UMAX_FORMAT PRIuMAX
typedef uintmax_t unsigned_max;
#elif defined ULLONG_MAX
#define UNSIGNED_MAX_MAX ULLONG_MAX
#define UMAX_FORMAT "llu"
typedef unsigned long long unsigned_max;
#else
#define UNSIGNED_MAX_MAX ULONG_MAX
#define UMAX_FORMAT "lu"
typedef unsigned long unsigned_max;
#endif
#elif defined ULLONG_MAX
#define UNSIGNED_MAX_MAX ULLONG_MAX
#define UMAX_FORMAT "llu"
typedef unsigned long long unsigned_max;
#else
#define UNSIGNED_MAX_MAX ULONG_MAX
#define UMAX_FORMAT "lu"
typedef unsigned long unsigned_max;
#endif
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
#if IMAX_BITS(UNSIGNED_MAX_MAX) > 16384
#error number of bits in UNSIGNED_MAX_MAX unreasonably high
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 8192
#define TM_WT_(T,v) TM_D_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 4096
#define TM_WT_(T,v) TM_C_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 2048
#define TM_WT_(T,v) TM_B_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 1024
#define TM_WT_(T,v) TM_A_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 512
#define TM_WT_(T,v) TM_9_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 256
#define TM_WT_(T,v) TM_8_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 128
#define TM_WT_(T,v) TM_7_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 64
#define TM_WT_(T,v) TM_6_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 32
#define TM_WT_(T,v) TM_5_(T,v)
#elif IMAX_BITS(UNSIGNED_MAX_MAX) > 16
#define TM_WT_(T,v) TM_4_(T,v)
#else
#error number of bits in UNSIGNED_MAX_MAX impossibly low
#endif
#define TM_D_(T,v) ( TM_OK(T,v>>8181) ? TM_C_(T,v) : TM_C_(T,(v>>8192)) )
#define TM_C_(T,v) ( TM_OK(T,v>>4095) ? TM_B_(T,v) : TM_B_(T,(v>>4096)) )
#define TM_B_(T,v) ( TM_OK(T,v>>2047) ? TM_A_(T,v) : TM_A_(T,(v>>2048)) )
#define TM_A_(T,v) ( TM_OK(T,v>>1023) ? TM_9_(T,v) : TM_9_(T,(v>>1024)) )
#define TM_9_(T,v) ( TM_OK(T,v>> 511) ? TM_8_(T,v) : TM_8_(T,(v>> 512)) )
#define TM_8_(T,v) ( TM_OK(T,v>> 255) ? TM_7_(T,v) : TM_7_(T,(v>> 256)) )
#define TM_7_(T,v) ( TM_OK(T,v>> 127) ? TM_6_(T,v) : TM_6_(T,(v>> 128)) )
#define TM_6_(T,v) ( TM_OK(T,v>> 63) ? TM_5_(T,v) : TM_5_(T,(v>> 64)) )
#define TM_5_(T,v) ( TM_OK(T,v>> 31) ? TM_4_(T,v) : TM_4_(T,(v>> 32)) )
#define TM_4_(T,v) ( TM_OK(T,v>> 15) ? TM_3_(T,v) : TM_3_(T,(v>> 16)) )
#define TM_3_(T,v) ( TM_OK(T,v>> 7) ? TM_2_(T,v) : TM_2_(T,(v>> 8)) )
#define TM_2_(T,v) ( TM_OK(T,v>> 3) ? TM_1_(T,v) : TM_1_(T,(v>> 4)) )
#define TM_1_(T,v) ( TM_OK(T,v>> 1) ? TM_0_(T,v) : TM_0_(T,(v>> 2)) )
#define TM_0_(T,v) ( TM_OK(T,v ) ? v : v>> 1 )
#define TM_OK(T,v) ( (T)(v) > 0 && (T)(v) == (v) )
#include <stddef.h>
#include <stdio.h>
char test_array[ TYPE_MAX(char) ];
int
main(){
printf( " sizeof test_array is %25" UMAX_FORMAT "\n",
(unsigned_max) sizeof test_array
);
printf( "\n" );
#if __STDC_VERSION__ > 199900L
printf( "Maximum value of _Bool is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(_Bool)
);
printf( "\n" );
#endif
printf( "Maximum value of char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(char)
);
printf( "Maximum value of signed char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed char)
);
printf( "Maximum value of unsigned char is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned char)
);
printf( "\n" );
printf( "Maximum value of signed short is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed short)
);
printf( "Maximum value of unsigned short is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned short)
);
printf( "\n" );
printf( "Maximum value of signed int is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed int)
);
printf( "Maximum value of unsigned int is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned int)
);
printf( "\n" );
printf( "Maximum value of signed long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed long)
);
printf( "Maximum value of unsigned long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned long)
);
printf( "\n" );
printf( "Maximum value of ptrdiff_t is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(ptrdiff_t)
);
printf( "Maximum value of size_t is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(size_t)
);
printf( "\n" );
#if __STDC_VERSION__ > 199900L
printf( "Maximum value of signed long long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(signed long long)
);
printf( "Maximum value of unsigned long long is %25" UMAX_FORMAT "\n",
(unsigned_max) TYPE_MAX(unsigned long long)
);
printf( "\n" );
#endif
printf( " Value of UNSIGNED_MAX_MAX is %25" UMAX_FORMAT "\n",
(unsigned_max) UNSIGNED_MAX_MAX
);
printf( "\n" );
printf( " UMAX_FORMAT is %25s\n", UMAX_FORMAT );
printf( "\n" );
return 0;
}