min and max value of data type in C
Solution 1:
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.
Solution 2:
"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.
Solution 3:
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 typet
have equal or larger size thanunsigned int
. (This cast forces type promotion.)((t)~0U)
// If you know your typet
have smaller size thanunsigned int
. (This cast demotes type after theunsigned int
-type expression~0U
is evaluated.)
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):
(((1ULL<<(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 -(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1
will work for you.
To detect whether your machine uses 2's complement, detect whether (~(t)0U)
and (t)(-1)
represent the same thing.
So, combined with above:
(-(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-(((~(t)0U)==(t)(-1)))
will give you the minimum value of any signed integral type.
As an example: 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.
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 incorpoating suggestions from @chux and @vinc17. Thank you both.)
Solution 4:
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;
}
Solution 5:
The header file limits.h
defines macros that expand to various limits and parameters of the standard integer types.