83

What is the function to determine the min and max possible of value of datatypes (i.e, int, char.etc) in C?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
SuperString
  • 21,593
  • 37
  • 91
  • 122

10 Answers10

99

You'll want to use limits.h which provides the following constants (as per the linked reference):

SCHAR_MIN      : minimum value for a signed char
SCHAR_MAX      : maximum value for a signed char
UCHAR_MAX      : maximum value for an unsigned char
CHAR_MIN       : minimum value for a char
CHAR_MAX       : maximum value for a char
SHRT_MIN       : minimum value for a short
SHRT_MAX       : maximum value for a short
USHRT_MAX      : maximum value for an unsigned short
INT_MIN        : minimum value for an int
INT_MAX        : maximum value for an int
UINT_MAX       : maximum value for an unsigned int
LONG_MIN       : minimum value for a long
LONG_MAX       : maximum value for a long
ULONG_MAX      : maximum value for an unsigned long
LLONG_MIN      : minimum value for a long long
LLONG_MAX      : maximum value for a long long
ULLONG_MAX     : maximum value for an unsigned long long
PTRDIFF_MIN    : minimum value of ptrdiff_t
PTRDIFF_MAX    : maximum value of ptrdiff_t
SIZE_MAX       : maximum value of size_t
SIG_ATOMIC_MIN : minimum value of sig_atomic_t
SIG_ATOMIC_MAX : maximum value of sig_atomic_t
WINT_MIN       : minimum value of wint_t
WINT_MAX       : maximum value of wint_t
WCHAR_MIN      : minimum value of wchar_t
WCHAR_MAX      : maximum value of wchar_t
CHAR_BIT       : number of bits in a char
MB_LEN_MAX     : maximum length of a multibyte character in bytes

Where U*_MIN is omitted for obvious reasons (any unsigned type has a minimum value of 0).

Similarly float.h provides limits for float and double types:

FLT_MIN    : smallest normalised positive value of a float
FLT_MAX    : largest positive finite value of a float
DBL_MIN    : smallest normalised positive value of a double
DBL_MAX    : largest positive finite value of a double
LDBL_MIN   : smallest normalised positive value of a long double
LDBL_MAX   : largest positive finite value of a long double
FLT_DIG    : the number of decimal digits guaranteed to be preserved converting from text to float and back to text
DBL_DIG    : the number of decimal digits guaranteed to be preserved converting from text to double and back to text
LDBL_DIG   : the number of decimal digits guaranteed to be preserved converting from text to long double and back to text

Floating point types are symmetrical around zero, so the most negative finite number is the negation of the most positive finite number - eg float ranges from -FLT_MAX to FLT_MAX.

Do note that floating point types can only exactly represent a small, finite number of values within their range. As the absolute values stored get larger, the spacing between adjacent numbers that can be exactly represented also gets larger.

BanksySan
  • 27,362
  • 33
  • 117
  • 216
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160
  • 2
    what is the min and max value of a float? – SuperString Jan 13 '10 at 02:10
  • 4
    `SIZE_MAX` (maximum size of a `size_t`) is another useful one. – caf Jan 13 '10 at 03:35
  • size_t maxSize = SIZE_MAX; – Joey van Hummel Apr 17 '14 at 20:12
  • @MartinBeckett not according to the header file, or my memories of writing this in C? FLT_MIN is approximately zero, no? – Adam Aug 12 '16 at 23:14
  • Downvoting because the answer is - simply - wrong. The question asks for min and max falue, and the header file only contains an answer for max value. Min value has to be calculated (happy to change my vote if someone comes along and corrects me, but my understanding/memory is that it's as per @JohnMudd's comment). "FLT_MIN = min value of a float" as written in this answer is absolutely WRONG. – Adam Aug 12 '16 at 23:16
  • adjusted; but you should note that the header files do include both min and max as labeled – Mark Elliot Aug 18 '16 at 02:39
  • `DBL_MAX = max value of a double` --> `DBL_MAX = max _finite_ value of a double`. A `double` infinity is a greater value than `DBL_MAX`. – chux - Reinstate Monica Jan 11 '18 at 21:11
  • @caf some systems have `SIZE_T_MAX` instead. There’s none for `time_t` though. I need a way to determine these at/before compile time, using compile checks (no run checks) only, and without triggering UB… – mirabilos Jan 22 '21 at 22:04
  • @mirabilos: `SIZE_MAX` is the standard-blessed macro, but that doesn't matter - `(size_t)-1` will be the maximum of `size_t` as well, because it's an unsigned type and per the rules on how out-of-range values are converted to unsigned types. That should work anywhere you have the definition of `size_t`. `time_t` is trickier, it could theoretically even be a floating-point type. – caf Jan 25 '21 at 04:00
  • @caf it could? UAAAAAAAAAAAAAAAAAAAH! How to detect that? – mirabilos Jan 25 '21 at 15:30
  • @mirabilos: It's only a theoretical possibility, I'm not aware of any real world implementation actually doing that. I suppose `(time_t)0.5 == 0.5` should do the trick. What do you need the maximum value of a `time_t` for anyway? – caf Jan 26 '21 at 22:50
  • @caf ugh, I don’t suppose this works in cpp… I must avoid using the FPU at all for all other cases. Let’s just call it esoteric and not worth bothering… hmm… I could do a configure-time check… (but how, without triggering the FPU-less environments…) • And: for overflow detection during input parsing. Something like `while (isdigit(*cp)) { i=*cp-'0'; if (v > (type_MAX / 10 - i)) error(); v=v*10+i; ++cp; }` (ofc not that breve but EBCDIC-safe, but that won’t fit in a comment), more specifically http://www.mirbsd.org/cvs.cgi/src/bin/sleep/sleep.c?rev=HEAD – mirabilos Jan 27 '21 at 00:22
  • Thankfully, POSIX has “time_t shall be an integer type” even if it is [CX shaded](https://pubs.opengroup.org/onlinepubs/9699919799/help/codes.html#CX). – mirabilos Jan 27 '21 at 00:28
  • 1
    @mirabilos: Right, your code seems to assume `struct timeval` which means you are in a world where `time_t` is an integer. Nevertheless you could do the input parsing in a known type (like `unsigned long long`), then convert to `time_t` and test whether the result is equal to the parsed `unsigned long long` value. Converting an out-of-range value to a type doesn't cause undefined behaviour, even for a signed type (though it can theoretically cause "an implementation-defined signal to be raised", I don't believe this is allowed in POSIX). – caf Jan 27 '21 at 03:22
  • I don’t think I’m guaranteed a known type at least as large as time_t, and the input should specifically allow all time_t values… I might go with a configure-time compile check for float… except: `$ gcc -c x.c -DT=float x.c:3:1: warning: variably modified ‘foo’ at file scope 3 | int foo[((T)0.5 == 0.5) ? 1 : -1];` – mirabilos Mar 02 '21 at 12:08
38

"But glyph", I hear you asking, "what if I have to determine the maximum value for an opaque type whose maximum might eventually change?" You might continue: "What if it's a typedef in a library I don't control?"

I'm glad you asked, because I just spent a couple of hours cooking up a solution (which I then had to throw away, because it didn't solve my actual problem).

You can use this handy maxof macro to determine the size of any valid integer type.

#define issigned(t) (((t)(-1)) < ((t) 0))

#define umaxof(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | \
                    (0xFULL << ((sizeof(t) * 8ULL) - 4ULL)))

#define smaxof(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | \
                    (0x7ULL << ((sizeof(t) * 8ULL) - 4ULL)))

#define maxof(t) ((unsigned long long) (issigned(t) ? smaxof(t) : umaxof(t)))

You can use it like so:

int main(int argc, char** argv) {
    printf("schar: %llx uchar: %llx\n", maxof(char), maxof(unsigned char));
    printf("sshort: %llx ushort: %llx\n", maxof(short), maxof(unsigned short));
    printf("sint: %llx uint: %llx\n", maxof(int), maxof(unsigned int));
    printf("slong: %llx ulong: %llx\n", maxof(long), maxof(unsigned long));
    printf("slong long: %llx ulong long: %llx\n",
           maxof(long long), maxof(unsigned long long));
    return 0;
}

If you'd like, you can toss a '(t)' onto the front of those macros so they give you a result of the type that you're asking about, and you don't have to do casting to avoid warnings.

BanksySan
  • 27,362
  • 33
  • 117
  • 216
Glyph
  • 31,152
  • 11
  • 87
  • 129
  • Wouldn't `~((t) 0)` work for max of unsigned? (it does not, but I am not sure why yet). – Gauthier Dec 05 '11 at 16:27
  • Thanks for the info on signedness detection. I'll update the answer. – Glyph Oct 26 '15 at 23:55
  • 2
    All of those 8ULL's constants should probably be CHAR_BIT instead. – jschultz410 Apr 11 '18 at 17:06
  • umaxof(t) can be much more easily written as ((t) -1) or (~(t) 0), which both are guaranteed to work by the C standard. smaxof(t) can be written ((t) ~(1ULL << (sizeof(t) * CHARBIT - 1))). Signed minimums are a lot trickier. – jschultz410 Apr 11 '18 at 17:41
  • 1
    Big thumbs up on maxof conditionally using the correct macro depending on issigned! – jschultz410 Apr 11 '18 at 17:42
  • 1
    @jschultz410 Your `smaxof(t)` as written as `((t) ~(1ULL << (sizeof(t) * CHARBIT - 1)))` will not work for integer types larger than `long long`. You could use `(uintmax_t)`, but note that in practice, one may have integer types larger than `uintmax_t` as extensions, such as GCC's `__int128`. My solution avoids such an issue and should work with C implementations that do not have `uintmax_t`. – vinc17 Apr 13 '18 at 07:27
  • @Gauthier `~((t) 0)` does not work when `(t)0` is narrower than an `int`. – chux - Reinstate Monica Apr 19 '19 at 02:43
  • 2
    `smaxof(t)` assumes 1) no padding and 2) 8 bits to a "byte". Reasonable assumptions, yet not specified by C. – chux - Reinstate Monica Apr 19 '19 at 02:46
  • 1
    `umaxof(t)` assumes no type wider that `unsigned long long`. Reasonable assumption, yet not specified by C. Using `uintmax_t` makes more sense. – chux - Reinstate Monica Apr 19 '19 at 02:47
9

Maximum value of any unsigned integral type:

  • ((t)~(t)0) // Generic expression that would work in almost all circumstances.

  • (~(t)0) // If you know your type t have equal or larger size than unsigned int. This cast forces type promotion.

  • ((t)~0U) // If you know your type t have equal or smaller size than unsigned int. This cast demotes type after the unsigned int-type expression ~0U is evaluated.

As an example: The maximum value of size_t (a.k.a. the SIZE_MAX macro) can be defined as (~(size_t)0). Linux kernel source code define SIZE_MAX macro this way.

Maximum value of any signed integral type:

  • If you have an unsigned variant of type t, ((t)(((unsigned t)~(unsigned t)0)>>1)) would give you the fastest result you need.

  • Otherwise, use this (thanks to @vinc17 for suggestion): (((t)1<<(sizeof(t)*CHAR_BIT-2))-1)*2+1

Minimum value of any signed integral type:

You have to know the signed number representation of your machine. Most machines use 2's complement, and so this will work for you:

-((((t)1<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1

/* Equivalent: */
(1-((t)1<<(sizeof(t)*CHAR_BIT-2)))*2-2

To detect whether your machine uses 2's complement, detect whether ((t)~(t)0) and (t)(-1) represent the same thing. Update (2022-03-24): (t) should be a signed type. The C99 standard mandates the conversion behavior from a signed integer type to unsigned. Regardless of the object representation of the value -N in a signed integer type, converting -N to unsigned always yields the value of one plus the maximum value of the unsigned type minus N. For example, (unsigned long)(-(N)) equals ULONG_MAX+1-(N).

Combined with above, this will give you the minimum value of any signed integral type:

-((((t)1<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-((t)~(t)0==(t)-1)

/* Equivalent: */
(1-((t)1<<(sizeof(t)*CHAR_BIT-2)))*2-1-((t)~(t)0==(t)-1)

One caveat though: All of these expressions use either type casting or sizeof operator and so none of these would work in preprocessor conditionals (#if ... #elif ... #endif and like).

(Answer updated for incorporating suggestions from @chux and @vinc17. Thank you both.)

Explorer09
  • 569
  • 5
  • 9
  • Note that `unsigned long long` may not be the largest integer type; `uintmax_t` should be better but isn't even always the largest integer type in practice (see GCC's `__int128`). I gave a more portable solution for the maximum of signed types in my answer. Then the minimum could be deduced from it as you did. Concerning the preprocessor conditionals, `sizeof` cannot be used either since preprocessing occurs before semantic analysis, i.e. the preprocessor doesn't have a notion of types. – vinc17 Apr 13 '18 at 08:08
  • "Maximum value of any signed integral type" method here relies on assumptions, albeit very common ones. Note that although uncommon, `xxx_MAX == Uxxx_MAX` is allowed in C as well as `xxx_MAX < Uxxx_MAX/2`. What is specifed is that `xxx_MAX <= Uxxx_MAX` and both types have the same size. – chux - Reinstate Monica Mar 09 '19 at 00:03
  • @chux For what I've known so far, `char` is the only C-standard type that could possibly satisfy `xxx_MAX == Uxxx_MAX`, as `char` may be signed or unsigned depending on implementation. And for the `xxx_MAX < Uxxx_MAX/2` case, it's most likely to be caused by non-2's-complement arithmetic (otherwise it won't make sense for an implementation). – Explorer09 Apr 18 '19 at 10:38
  • `char` types do not allow padding. Other integer types may pad (something this answer assumes to not exist - yet C allows it), although that is very uncommon - have not come across such an implementation in over 10y. Because of that `ULLONG_MAX == LLONG_MAX` is possible. The issue applies even with 2's complement. – chux - Reinstate Monica Apr 18 '19 at 13:23
  • 1
    `~((t) 0)` does not work when `(t)0` is narrower than an `int`. – chux - Reinstate Monica Apr 19 '19 at 02:49
  • 1
    @chux Thanks for the hint about `~((t) 0)`. As for the `xxx_MAX == Uxxx_MAX` and `xxx_MAX < Uxxx_MAX/2` cases, from what I've read in the C99 standard, yes they are allowed. – Explorer09 Apr 19 '19 at 05:06
  • `1ULL` fails with some pre-C99 compilers, for example. Can’t we just use `((t)1)`? – mirabilos Jan 22 '21 at 22:23
3

The header file limits.h defines macros that expand to various limits and parameters of the standard integer types.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
3

I wrote some macros that return the min and max of any type, regardless of signedness:

#define MAX_OF(type) \
    (((type)(~0LLU) > (type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) ? (long long unsigned int)(type)(~0LLU) : (long long unsigned int)(type)((1LLU<<((sizeof(type)<<3)-1))-1LLU))
#define MIN_OF(type) \
    (((type)(1LLU<<((sizeof(type)<<3)-1)) < (type)1) ? (long long int)((~0LLU)-((1LLU<<((sizeof(type)<<3)-1))-1LLU)) : 0LL)

Example code:

#include <stdio.h>
#include <sys/types.h>
#include <inttypes.h>

#define MAX_OF(type) \
    (((type)(~0LLU) > (type)((1LLU<<((sizeof(type)<<3)-1))-1LLU)) ? (long long unsigned int)(type)(~0LLU) : (long long unsigned int)(type)((1LLU<<((sizeof(type)<<3)-1))-1LLU))
#define MIN_OF(type) \
    (((type)(1LLU<<((sizeof(type)<<3)-1)) < (type)1) ? (long long int)((~0LLU)-((1LLU<<((sizeof(type)<<3)-1))-1LLU)) : 0LL)

int main(void)
{
    printf("uint32_t = %lld..%llu\n", MIN_OF(uint32_t), MAX_OF(uint32_t));
    printf("int32_t = %lld..%llu\n", MIN_OF(int32_t), MAX_OF(int32_t));
    printf("uint64_t = %lld..%llu\n", MIN_OF(uint64_t), MAX_OF(uint64_t));
    printf("int64_t = %lld..%llu\n", MIN_OF(int64_t), MAX_OF(int64_t));
    printf("size_t = %lld..%llu\n", MIN_OF(size_t), MAX_OF(size_t));
    printf("ssize_t = %lld..%llu\n", MIN_OF(ssize_t), MAX_OF(ssize_t));
    printf("pid_t = %lld..%llu\n", MIN_OF(pid_t), MAX_OF(pid_t));
    printf("time_t = %lld..%llu\n", MIN_OF(time_t), MAX_OF(time_t));
    printf("intptr_t = %lld..%llu\n", MIN_OF(intptr_t), MAX_OF(intptr_t));
    printf("unsigned char = %lld..%llu\n", MIN_OF(unsigned char), MAX_OF(unsigned char));
    printf("char = %lld..%llu\n", MIN_OF(char), MAX_OF(char));
    printf("uint8_t = %lld..%llu\n", MIN_OF(uint8_t), MAX_OF(uint8_t));
    printf("int8_t = %lld..%llu\n", MIN_OF(int8_t), MAX_OF(int8_t));
    printf("uint16_t = %lld..%llu\n", MIN_OF(uint16_t), MAX_OF(uint16_t));
    printf("int16_t = %lld..%llu\n", MIN_OF(int16_t), MAX_OF(int16_t));
    printf("int = %lld..%llu\n", MIN_OF(int), MAX_OF(int));
    printf("long int = %lld..%llu\n", MIN_OF(long int), MAX_OF(long int));
    printf("long long int = %lld..%llu\n", MIN_OF(long long int), MAX_OF(long long int));
    printf("off_t = %lld..%llu\n", MIN_OF(off_t), MAX_OF(off_t));

    return 0;
}
craig65535
  • 3,439
  • 1
  • 23
  • 49
3
#include<stdio.h>

int main(void)
{
    printf("Minimum Signed Char %d\n",-(char)((unsigned char) ~0 >> 1) - 1);
    printf("Maximum Signed Char %d\n",(char) ((unsigned char) ~0 >> 1));

    printf("Minimum Signed Short %d\n",-(short)((unsigned short)~0 >>1) -1);
    printf("Maximum Signed Short %d\n",(short)((unsigned short)~0 >> 1));

    printf("Minimum Signed Int %d\n",-(int)((unsigned int)~0 >> 1) -1);
    printf("Maximum Signed Int %d\n",(int)((unsigned int)~0 >> 1));

    printf("Minimum Signed Long %ld\n",-(long)((unsigned long)~0 >>1) -1);
    printf("Maximum signed Long %ld\n",(long)((unsigned long)~0 >> 1));

    /* Unsigned Maximum Values */

    printf("Maximum Unsigned Char %d\n",(unsigned char)~0);
    printf("Maximum Unsigned Short %d\n",(unsigned short)~0);
    printf("Maximum Unsigned Int %u\n",(unsigned int)~0);
    printf("Maximum Unsigned Long %lu\n",(unsigned long)~0);

    return 0;
}
  • We can simply get highest value of unsigned data type and subtract it from maximum value to get minimum value. – Akansh Nov 19 '17 at 20:18
  • 1
    This is a great, system-independent answer that demonstrates an understanding of types, memory, and of course of C bitwise operators. – Jonathan Komar Feb 07 '18 at 07:47
  • 1
    @JonathanKomar All of the above signed minimums assume a 2's complement architecture, which is usually -- but not always -- the case in C. – jschultz410 Apr 11 '18 at 17:36
  • 1
    Correction: system-dependent (assumes a 2‘s complement interpretation of bits) Thanks jschultz410. – Jonathan Komar Oct 18 '18 at 13:32
2

Look at the these pages on limits.h and float.h, which are included as part of the standard c library.

Nixuz
  • 3,439
  • 4
  • 39
  • 44
2

To get the maximum value of an unsigned integer type t whose width is at least the one of unsigned int (otherwise one gets problems with integer promotions): ~(t) 0. If one wants to also support shorter types, one can add another cast: (t) ~(t) 0.

If the integer type t is signed, assuming that there are no padding bits, one can use:

((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1)

The advantage of this formula is that it is not based on some unsigned version of t (or a larger type), which may be unknown or unavailable (even uintmax_t may not be sufficient with non-standard extensions). Example with 6 bits (not possible in practice, just for readability):

010000  (t) 1 << (sizeof(t) * CHAR_BIT - 2)
001111  - 1
011110  * 2
011111  + 1

In two's complement, the minimum value is the opposite of the maximum value, minus 1 (in the other integer representations allowed by the ISO C standard, this is just the opposite of the maximum value).

Note: To detect signedness in order to decide which version to use: (t) -1 < 0 will work with any integer representation, giving 1 (true) for signed integer types and 0 (false) for unsigned integer types. Thus one can use:

(t) -1 < 0 ? ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1) : (t) ~(t) 0
vinc17
  • 2,829
  • 17
  • 23
  • For signed max, why not more simply (~((t) 1 << (sizeof(t) * CHAR_BIT - 1)))? – jschultz410 Apr 11 '18 at 17:34
  • 1
    @jschultz410 Because this is undefined behavior. The mathematical (and positive) value 2 to the `sizeof(t) * CHAR_BIT - 1` is not representable in the signed type `t`. You're assuming "wrapping" behavior of the left shift, which is not standard (and may fail with optimizing compilers) and would not even make sense in the integer representations different from two's complement (as allowed by the C standard). – vinc17 Apr 13 '18 at 07:13
0

MIN and MAX values of any integer data type can be computed without using any library functions as below and same logic can be applied to other integer types short, int and long.

printf("Signed Char : MIN -> %d & Max -> %d\n", ~(char)((unsigned char)~0>>1), (char)((unsigned char)~0 >> 1));
printf("Unsigned Char : MIN -> %u & Max -> %u\n", (unsigned char)0, (unsigned char)(~0));
Arjun
  • 1
  • 1
0

Just to complement other answers one can mention that C99 defines macros like INT8_MAX, UINT8_MAX, INT16_MAX, UINT16_MAX etc. in the stdint.h header. See, e.g., this link.

Pavel Shishpor
  • 742
  • 6
  • 14