Минимальное и максимальное значение типа данных в 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 определяет макросы, которые расширяются до различных пределов и параметров стандартных целочисленных типов.

Посмотрите на эти страницы на limit.h и float.h, которые включены в стандартную библиотеку c.

Чтобы получить максимальное значение целого типа без знака 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));
Другие вопросы по тегам