Минимальное и максимальное значение типа данных в C
Какова функция для определения минимального и максимального возможных значений типов данных (то есть, int, char.etc) в C?
10 ответов
Вы хотите использовать limits.h
который обеспечивает следующие константы (согласно связанной ссылке):
CHAR_BIT = number of bits in a char
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
MB_LEN_MAX = maximum multibyte length of a character accross locales
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
куда U*_MIN
опущен по понятным причинам (любой тип без знака имеет минимальное значение 0).
так же float.h
устанавливает ограничения для float
а также double
типы:
-FLT_MAX = most negative value of a float
FLT_MAX = max value of a float
-DBL_MAX = most negative value of a double
DBL_MAX = max value of a double
-LDBL_MAX = most negative value of a long double
LDBL_MAX = max value of a long double
Вы должны прочитать статью на floats.h
осторожно, хотя float
а также double
может содержать предписанные минимальное и максимальное значения, но точность, с которой каждый тип может представлять данные, может не соответствовать тому, что вы пытаетесь сохранить. В частности, трудно хранить исключительно большие числа с очень малыми фракциями. Так float.h
предоставляет ряд других констант, которые помогут вам определить, является ли float
или double
фактически может представлять определенное число.
"Но глиф, - слышу ты, спрашиваешь, - а что, если мне нужно определить максимальное значение для непрозрачного типа, чей максимум в конечном итоге может измениться?" Вы можете продолжить: "Что если это typedef в библиотеке, которой я не управляю?"
Я рад, что вы спросили, потому что я просто потратил пару часов, готовя решение (которое я затем должен был выбросить, потому что оно не решило мою реальную проблему).
Вы можете использовать этот удобный maxof
макрос для определения размера любого допустимого целочисленного типа.
#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)))
Вы можете использовать это так:
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;
}
Если вы хотите, вы можете добавить '(t)' в начало этих макросов, чтобы они дали вам результат типа, о котором вы спрашиваете, и вам не нужно выполнять приведение, чтобы избежать предупреждений.
Максимальное значение любого целого типа без знака: (~(t)0)
Максимальное значение любого целого типа со знаком: если у вас есть вариант без знака типа t, ((t)((~(unsigned t)0)>>1))
даст вам самый быстрый результат, который вам нужен (см. пример в исходном коде ядра Linux, указанном ниже). В противном случае, вы, вероятно, должны использовать (~(1ULL<<(sizeof(t)*CHAR_BIT-1)))
,
Минимальное значение любого целого типа со знаком: Вы должны знать представление числа со знаком вашей машины. Большинство машин используют 2 дополнения, и поэтому -(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1
будет работать на вас.
Чтобы определить, использует ли ваша машина 2 дополнения, определите, (~(t)0U)
а также (t)(-1)
представлять то же самое. Итак, в сочетании с вышесказанным:
((~(t)0U) == (t)(-1) ? -(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1 :
-(~(1ULL<<(sizeof(t)*CHAR_BIT-1))))
даст вам минимальное значение любого целого типа со знаком. (На самом деле есть другие представления об этом, если вы знаете представление дополнения 2. Например, (t)(1ULL<<(sizeof(t)*CHAR_BIT-1))
должно быть эквивалентно (t)(-(~(1ULL<<(sizeof(t)*CHAR_BIT-1)))-1)
.)
Например: (~(size_t)0) дает вам максимальное значение size_t. (И угадайте, что именно так SIZE_MAX определяется в исходном коде ядра Linux.)
Одно предостережение: все эти выражения используют приведение типов и поэтому не работают в условных выражениях препроцессора (#if ... #elif ... #endif и т.п.).
Я написал несколько макросов, которые возвращают минимальное и максимальное значения любого типа, независимо от подписи:
#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)
Пример кода:
#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;
}
#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;
}
Заголовочный файл limits.h
определяет макросы, которые расширяются до различных пределов и параметров стандартных целочисленных типов.
Чтобы получить максимальное значение целого типа без знака t
ширина которого по крайней мере одна из unsigned int
(в противном случае возникают проблемы с целочисленными акциями): ~(t) 0
, Если вы хотите также поддерживать более короткие типы, вы можете добавить другое приведение: (t) ~(t) 0
,
Если целочисленный тип t
подписано, при условии, что нет битов заполнения, можно использовать:
((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1)
Преимущество этой формулы в том, что она не основана на какой-либо неподписанной версии t
(или более крупный тип), который может быть неизвестен или недоступен (даже uintmax_t
может быть недостаточно для нестандартных расширений). Пример с 6 битами (на практике это невозможно, просто для удобства чтения):
010000 (t) 1 << (sizeof(t) * CHAR_BIT - 2)
001111 - 1
011110 * 2
011111 + 1
В дополнение к двум, минимальное значение противоположно максимальному значению, минус 1 (в других целочисленных представлениях, допускаемых стандартом ISO C, это как раз противоположно максимальному значению).
Примечание. Чтобы определить подпись, чтобы решить, какую версию использовать: (t) -1 < 0
будет работать с любым целочисленным представлением, давая 1 (true) для целочисленных типов со знаком и 0 (false) для целочисленных типов без знака. Таким образом можно использовать:
(t) -1 < 0 ? ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1) : (t) ~(t) 0
Чтобы дополнить другие ответы, можно упомянуть, что C99 определяет такие макросы, какINT8_MAX
,UINT8_MAX
,INT16_MAX
,UINT16_MAX
и т. д. вstdint.h
заголовок. См., например, эту ссылку .
Значения MIN и MAX любого целочисленного типа данных могут быть вычислены без использования каких-либо библиотечных функций, как показано ниже, и та же логика может быть применена к другим целочисленным типам short, int и 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));