Мин и максимальное значение типа данных в C

Какова функция определения минимального и максимального возможного значения типов данных (т.е. int, char.etc) в C?

Ответ 1

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

Ответ 2

"Но глиф", я слышу, что вы спрашиваете: "Что, если мне нужно определить максимальное значение для непрозрачного типа, чей максимум может в конечном итоге измениться?" Вы можете продолжить: "Что, если это 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)" на переднюю часть этих макросов, чтобы они дали вам результат типа, о котором вы просите, и вам не нужно делать листинг избегайте предупреждений.

Ответ 3

Максимальное значение любого целого типа без знака:

  • ((t)~(t)0)//Общее выражение, которое будет работать практически при любых обстоятельствах.

  • (~(t)0)//Если вы знаете, что ваш тип t имеет такой же или больший размер, чем unsigned int. (Это приведение типа силы продвижения).

  • ((t)~0U)//Если вы знаете, что ваш тип t имеет меньший размер, чем unsigned int. (Это приведение понижает тип после вычисления выражения unsigned int -type ~0U.)

Максимальное значение любого целого типа со знаком:

  • Если у вас есть вариант без знака типа t, ((t)(((unsigned t)~(unsigned t)0)>>1)) даст вам самый быстрый результат, который вам нужен.

  • В противном случае используйте это (спасибо @vinc17 за предложение): (((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)

Минимальное значение любого целого типа со знаком:

Вы должны знать числовое представление вашей машины. Большинство машин используют 2 дополнения, и поэтому -(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1 будет работать для вас.

Чтобы определить, использует ли ваша машина 2 дополнения, определите, представляют ли (~(t)0U) и (t)(-1) одно и то же.

Итак, в сочетании с вышесказанным:

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

даст вам минимальное значение любого целого типа со знаком.

В качестве примера: максимальное значение size_t (или макрос SIZE_MAX) можно определить как (~(size_t)0). Исходный код ядра Linux определяет макрос SIZE_MAX таким образом.

Одно предостережение: все эти выражения используют либо приведение типа, либо оператор sizeof поэтому ни одно из них не будет работать в условных #elif препроцессора (#if... #elif... #endif и т.д.).

(Ответ обновлен за включение предложений от @chux и @vinc17. Спасибо вам обоим.)

Ответ 4

#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;
}

Ответ 5

В файле заголовка limits.h определяются макросы, которые расширяются до различных ограничений и параметров стандартных целых типов.

Ответ 6

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

Ответ 7

Я написал несколько макросов, которые возвращают min и max любого типа, независимо от подписанности:

#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;
}

Ответ 8

Чтобы получить максимальное значение целочисленного типа без знака 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) для целых типов со (t) -1 < 0 и 0 (false) для целых типов без знака. Таким образом можно использовать:

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

Ответ 9

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));