【问题标题】:min and max value of data type in CC中数据类型的最小值和最大值
【发布时间】:2011-01-04 11:03:27
【问题描述】:

在 C 中确定数据类型(即 int、char.etc)的最小值和最大值的函数是什么?

【问题讨论】:

    标签: c types


    【解决方案1】:

    您需要使用limits.h,它提供以下常量(根据链接参考):

    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
    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
    PTRDIFF_MIN    : minimum value of ptrdiff_t
    PTRDIFF_MAX    : maximum value of ptrdiff_t
    SIZE_MAX       : maximum value of size_t
    SIG_ATOMIC_MIN : minimum value of sig_atomic_t
    SIG_ATOMIC_MAX : maximum value of sig_atomic_t
    WINT_MIN       : minimum value of wint_t
    WINT_MAX       : maximum value of wint_t
    WCHAR_MIN      : minimum value of wchar_t
    WCHAR_MAX      : maximum value of wchar_t
    CHAR_BIT       : number of bits in a char
    MB_LEN_MAX     : maximum length of a multibyte character in bytes
    

    U*_MIN 出于明显的原因被省略(任何无符号类型的最小值为 0)。

    同样float.hfloatdouble 类型提供限制:

    FLT_MIN    : smallest normalised positive value of a float
    FLT_MAX    : largest positive finite value of a float
    DBL_MIN    : smallest normalised positive value of a double
    DBL_MAX    : largest positive finite value of a double
    LDBL_MIN   : smallest normalised positive value of a long double
    LDBL_MAX   : largest positive finite value of a long double
    FLT_DIG    : the number of decimal digits guaranteed to be preserved converting from text to float and back to text
    DBL_DIG    : the number of decimal digits guaranteed to be preserved converting from text to double and back to text
    LDBL_DIG   : the number of decimal digits guaranteed to be preserved converting from text to long double and back to text
    

    浮点类型围绕零对称,因此最负的有限数是最正的有限数的否定 - 例如,float 的范围从 -FLT_MAXFLT_MAX

    请注意,浮点类型只能精确表示其范围内的一小部分有限数量的值。随着存储的绝对值越来越大,可以精确表示的相邻数字之间的间距也越来越大。

    【讨论】:

    • 浮点数的最小值和最大值是多少?
    • SIZE_MAXsize_t 的最大大小)是另一个有用的方法。
    • size_t maxSize = SIZE_MAX;
    • @MartinBeckett 不是根据头文件,还是我记忆中用 C 写的? FLT_MIN 大约为零,不是吗?
    • @mirabilos:是的,您的代码似乎假定struct timeval 这意味着您处于time_t 是整数的世界中。不过,您可以以已知类型(如unsigned long long)进行输入解析,然后转换为time_t 并测试结果是否等于解析的unsigned long long 值。将超出范围的值转换为类型不会导致未定义的行为,即使对于带符号的类型也是如此(尽管理论上它可以导致“引发实现定义的信号”,但我不相信这在 POSIX 中是允许的)。
    【解决方案2】:

    头文件limits.h 定义了扩展为标准整数类型的各种限制和参数的宏。

    【讨论】:

    • unsigned char 的最小值是多少?
    • @Superstring,任何unsigned类型的最小值都是0。
    • 我想要负的无符号值! :-)
    【解决方案3】:

    查看limits.hfloat.h 上的这些页面,它们是标准c 库的一部分。

    【讨论】:

      【解决方案4】:

      “但是字形”,我听到你在问,“如果我必须确定最大值可能最终会改变的不透明类型的最大值怎么办?”您可能会继续:“如果它是我无法控制的库中的 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) 不会为最大的未签名工作? (它没有,但我不知道为什么)。
      • 所有这些 8ULL 的常量可能应该是 CHAR_BIT。
      • 对 maxof 大赞有条件地使用正确的宏,具体取决于已签名!
      • @jschultz410 写成((t) ~(1ULL &lt;&lt; (sizeof(t) * CHARBIT - 1)))smaxof(t) 不适用于大于long long 的整数类型。您可以使用(uintmax_t),但请注意,在实践中,可能具有大于uintmax_t 的整数类型作为扩展名,例如GCC 的__int128。我的解决方案避免了这样的问题,并且应该与没有 uintmax_t 的 C 实现一起使用。
      • smaxof(t) 假设 1) 没有填充和 2) 8 位到一个“字节”。合理的假设,但 C 未指定。
      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        任何整数数据类型的 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));
        

        【讨论】:

          【解决方案7】:

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

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

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

          • ((t)~0U) // 如果你知道你的类型 t 的大小小于 unsigned int。 (此转换将unsigned int-type 之后的类型降级 表达式~0U 被计算。)

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

          • 如果您有 t 类型的无符号变体,((t)(((unsigned t)~(unsigned t)0)&gt;&gt;1)) 将为您提供所需的最快结果。

          • 否则,使用这个(感谢@vinc17 的建议):(((1ULL&lt;&lt;(sizeof(t)*CHAR_BIT-2))-1)*2+1)

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

          您必须知道您的机器的签名数字表示。大多数机器都使用 2 的补码,所以 -(((1ULL&lt;&lt;(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 kernel source code 以这种方式定义 SIZE_MAX 宏。

          一个警告:所有这些表达式都使用类型转换或sizeof 运算符,因此这些都不能在预处理器条件下工作(#if ... #elif ... #endif 等)。

          (已更新答案以包含来自 @chux 和 @vinc17 的建议。谢谢你们。)

          【讨论】:

          • 注意unsigned long long可能不是最大的整数类型; uintmax_t 应该更好,但实际上并不总是最大的整数类型(参见 GCC 的 __int128)。我在我的答案中为最大的签名类型提供了一个更便携的解决方案。然后可以像您一样从中推断出最小值。关于预处理器条件,sizeof 也不能使用,因为预处理发生在语义分析之前,即预处理器没有类型的概念。
          • “任何有符号整数类型的最大值”方法在这里依赖于假设,尽管是非常常见的假设。请注意,尽管不常见,xxx_MAX == Uxxx_MAX 在 C 和 xxx_MAX &lt; Uxxx_MAX/2 中都是允许的。指定的是xxx_MAX &lt;= Uxxx_MAX 和两种类型的大小相同。
          • @chux 就我目前所知,char 是唯一可能满足xxx_MAX == Uxxx_MAX 的C 标准类型,因为char 可能是有符号或无符号的,具体取决于实现。而对于xxx_MAX &lt; Uxxx_MAX/2 的情况,它很可能是由非2 的补码算法引起的(否则它对实现没有意义)。
          • (t)0int 窄时,~((t) 0) 不起作用。
          • @chux 感谢有关~((t) 0) 的提示。至于xxx_MAX == Uxxx_MAXxxx_MAX &lt; Uxxx_MAX/2 的情况,从我在C99 标准中阅读的内容来看,是的,它们是允许的。
          【解决方案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 &lt; 0 将适用于任何整数表示,为有符号整数类型提供 1(真),为无符号整数类型提供 0(假)。因此可以使用:

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

          【讨论】:

          • 对于有符号最大值,为什么不更简单 (~((t) 1
          • @jschultz410 因为这是未定义的行为。 sizeof(t) * CHAR_BIT - 1 的数学(和正)值 2 不能在有符号类型 t 中表示。您假设左移的“包装”行为,这不是标准的(并且可能会因优化编译器而失败),并且在不同于二进制补码的整数表示中甚至没有意义(如 C 标准所允许的那样)。跨度>
          【解决方案9】:
          #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;
          }
          

          【讨论】:

          • 我们可以简单地得到无符号数据类型的最大值,然后从最大值中减去它得到最小值。
          • 这是一个很好的、独立于系统的答案,展示了对类型、内存以及 C 位运算符的理解。
          • @JonathanKomar 上述所有带符号的最小值都假定一个 2 的补码架构,这通常是——但并非总是——在 C 中的情况。
          • 更正:系统相关(假设位的 2 补码解释)感谢 jschultz410。
          猜你喜欢
          • 2019-01-02
          • 1970-01-01
          • 1970-01-01
          • 2011-03-27
          • 1970-01-01
          • 2017-02-13
          • 1970-01-01
          • 1970-01-01
          • 2011-12-18
          相关资源
          最近更新 更多