C中数据类型的最小值和最大值


76

确定C中数据类型(例如int,char.etc)值的最小值和最大值的功能是什么?

Answers:


92

您将要使用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),省略了where 。

同样float.h提供了以下限制floatdouble类型:

-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
浮点数的最小值和最大值是多少?
SuperString 2010年

3
SIZE_MAX(a的最大大小size_t)是另一种有用的方法。
caf 2010年

size_t maxSize = SIZE_MAX;
Joey van Hummel

2
-FLT_MAX和FLT_MAX
JohnMudd 2014年

@MartinBeckett不是根据头文件,还是我用C编写此文件的记忆?FLT_MIN大约为零,不是吗?
亚当

32

我听到您在问“但是字形”,如果我必须确定一个不透明类型的最大值,该最大值最终可能会改变?您可能会继续:“如果它是我无法控制的库中的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)为最大数量的unsigned工作吗?(没有,但是我不确定为什么)。
Gauthier

感谢您提供有关签名检测的信息。我将更新答案。
雕文

1
所有这些8ULL常量都应该改为CHAR_BIT。
jschultz410 '18

umaxof(t)可以更容易地写为((t)-1)或(〜(t)0),它们都可以通过C标准来保证正常工作。可以写入smaxof(t)((t)〜(1ULL <<(sizeof(t)* CHARBIT-1)))。签署的最低要求要复杂得多。
jschultz410

取决于issigned,有条件地使用正确的宏对maxof表示赞许!
jschultz410 '18

7

任何无符号整数类型的最大值

  • ((t)~(t)0) //几乎在所有情况下都适用的通用表达式。

  • (~(t)0)//如果知道类型的t大小等于或大于 unsigned int。(此演员强制类型提升。)

  • ((t)~0U)//如果知道类型的t大小小于 unsigned int。(在对unsigned int-type表达式~0U求值后,此强制转换类型降级。)

任何有符号整数类型的最大值

  • 如果您有类型的unsigned变体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运营商等等这些都不将于预处理条件工作(#if... #elif...#endif和等)。

(更新了有关合并来自@chux和@ vinc17的建议的答案。谢谢你们。)


注意,它unsigned long long可能不是最大的整数类型。uintmax_t应该更好,但实际上也不总是最大的整数类型(请参阅GCC的__int128)。对于答案中的最大签名类型,我给出了一个更可移植的解决方案。然后可以像您所做的那样推导出最小值。关于预处理器的条件,sizeof由于预处理发生在语义分析之前,即预处理器没有类型概念,因此不能使用预处理器。
vinc17

这里的“任何带符号整数类型的最大值”方法都基于假设,尽管这些假设非常普遍。请注意,尽管不常见,但xxx_MAX == Uxxx_MAXC和中都允许xxx_MAX < Uxxx_MAX/2。指定的是这xxx_MAX <= Uxxx_MAX两种类型的大小都相同。
chux-恢复莫妮卡

@chux为了什么我迄今所知,char是唯一的C-标准型那些可能满足xxx_MAX == Uxxx_MAX,因为char可以根据实施来带符号。对于这种xxx_MAX < Uxxx_MAX/2情况,它最有可能是由非2的补码算法引起的(否则对实现没有意义)。
Explorer09

1
~((t) 0)(t)0比窄时不起作用int
chux-恢复莫妮卡

1
@chux感谢您的提示~((t) 0)。至于xxx_MAX == Uxxx_MAXxxx_MAX < Uxxx_MAX/2案例,从我在C99标准中所读的内容来看,是的,它们是允许的。
Explorer09

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

我们可以简单地获取无符号数据类型的最大值,然后从最大值中减去它以获得最小值。
阿肯什(Akansh),

1
这是一个很棒的,独立于系统的答案,它表明了对类型,内存以及C语言位运算符的理解。
乔纳森·科马尔

的@JonathanKomar所有签署上述最低假设2的补架构,这通常是-但并不总是-在C的情况下
jschultz410

校正:与系统有关(假设位的2的补码解释)感谢jschultz410。
乔纳森·科玛


3

我写了一些宏,它们返回任何类型的最小值和最大值,而不考虑符号性:

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


2

为了得到一个无符号整数类型的最大值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

对于有符号的最大值,为什么不更简单(〜((t)1 <<(sizeof(t)* CHAR_BIT-1)))?
jschultz410

1
@ jschultz410因为这是未定义的行为。的数学(正)值2sizeof(t) * CHAR_BIT - 1在有符号类型中无法表示t。您假设左移是“包装”行为,这不是标准的操作(在优化编译器时可能会失败),甚至在不同于2的补码的整数表示形式(C标准所允许的)中也没有意义。
vinc17

0

无需使用以下任何库函数,就可以计算任何整数数据类型的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));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.