确定C中数据类型(例如int,char.etc)值的最小值和最大值的功能是什么?
Answers:
您将要使用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
提供了以下限制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
罐头或罐头是否实际上代表一个特定的数字。
SIZE_MAX
(a的最大大小size_t
)是另一种有用的方法。
我听到您在问“但是字形”,如果我必须确定一个不透明类型的最大值,该最大值最终可能会改变?您可能会继续:“如果它是我无法控制的库中的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工作吗?(没有,但是我不确定为什么)。
任何无符号整数类型的最大值:
((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
由于预处理发生在语义分析之前,即预处理器没有类型概念,因此不能使用预处理器。
xxx_MAX == Uxxx_MAX
C和中都允许xxx_MAX < Uxxx_MAX/2
。指定的是这xxx_MAX <= Uxxx_MAX
两种类型的大小都相同。
char
是唯一的C-标准型那些可能满足xxx_MAX == Uxxx_MAX
,因为char
可以根据实施来带符号。对于这种xxx_MAX < Uxxx_MAX/2
情况,它最有可能是由非2的补码算法引起的(否则对实现没有意义)。
~((t) 0)
(t)0
比窄时不起作用int
。
~((t) 0)
。至于xxx_MAX == Uxxx_MAX
和xxx_MAX < Uxxx_MAX/2
案例,从我在C99标准中所读的内容来看,是的,它们是允许的。
#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;
}
我写了一些宏,它们返回任何类型的最小值和最大值,而不考虑符号性:
#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;
}
头文件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
sizeof(t) * CHAR_BIT - 1
在有符号类型中无法表示t
。您假设左移是“包装”行为,这不是标准的操作(在优化编译器时可能会失败),甚至在不同于2的补码的整数表示形式(C标准所允许的)中也没有意义。