Introspect类型min / max with C

时间:2014-07-28 05:30:00

标签: c types c-preprocessor

我想知道在C中是否有某种方式来反省一种类型的最大值。

例如,我有一个名为a的变量,它是unsigned short ...

{
    unsigned short a;
    long long max = TYPEOF_MAX(a);
    /* now max will be USHRT_MAX */
}

{
    signed char a;
    long long max = TYPEOF_MAX(a);
    /* now max will be CHAR_MAX */
}

其中TYPEOF_MAX是一个宏,它使用某种方法来获取基于类型的范围(这是静态的)。

其他资格赛......

  • 如果仅限于几种类型,例如char/short/int/long/long long/float/double
  • ,则可以
  • 这可能需要使用一些C扩展,GCC甚至C11,但更喜欢更便携的方法。

注意:这适用于生成的代码,显然包括<lmits.h>,使用USHRT_MAXCHAR_MAX几乎在所有情况下都能正常工作

4 个答案:

答案 0 :(得分:6)

我从来没有做过c11,但它确实有一个可以帮助你的功能,根据维基百科称为&#34;类型通用表达式&#34;。据我所知,你可以做_Generic(a, int: INT_MAX, long: LONG_MAX, default: SOME_MANINGFUL_DEFAULT_VALUE)。这将检查a的类型,并根据其类型选择要评估的表达式,这将是类型泛型表达式的结果。

它不是最好的解决方案,但你要做的就是拥有一个使用_Generic的宏,并处理你感兴趣的所有算术类型。

GCC 4.9(https://gcc.gnu.org/wiki/C11Status)似乎支持它。

维基百科页面可能比我更好地解释它:http://en.wikipedia.org/wiki/C11_(C_standard_revision)

答案 1 :(得分:2)

这是一个使用GCC __builtin_types_compatible_p的解决方案,虽然它有效,但它有以下缺点。

  • 仅限GCC(无MSVC)
  • 缺少类型不会在构建时失败(而是在运行时)。
  • 不能在功能之外使用。
  • 不被视为常量,因此您不能使用static-assert作为示例。

示例代码:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <math.h>
#include <float.h>

#define TYPEOF_MAX(x)                                                         \
  ({                                                                          \
    typeof(x) tmp;                                                            \
    if      (__builtin_types_compatible_p(typeof(x), signed char))            \
      tmp = (typeof(x))CHAR_MAX;                                              \
    else if (__builtin_types_compatible_p(typeof(x), unsigned char))          \
      tmp = (typeof(x))UCHAR_MAX;                                             \
    else if (__builtin_types_compatible_p(typeof(x), signed short))           \
      tmp = (typeof(x))SHRT_MAX;                                              \
    else if (__builtin_types_compatible_p(typeof(x), unsigned short))         \
      tmp = (typeof(x))USHRT_MAX;                                             \
    else if (__builtin_types_compatible_p(typeof(x), signed int))             \
      tmp = (typeof(x))INT_MAX;                                               \
    else if (__builtin_types_compatible_p(typeof(x), unsigned int))           \
      tmp = (typeof(x))UINT_MAX;                                              \
    else if (__builtin_types_compatible_p(typeof(x), signed long))            \
      tmp = (typeof(x))LONG_MAX;                                              \
    else if (__builtin_types_compatible_p(typeof(x), unsigned long))          \
      tmp = (typeof(x))ULONG_MAX;                                             \
    else if (__builtin_types_compatible_p(typeof(x), float))                  \
      tmp = (typeof(x))FLT_MAX;                                               \
    else if (__builtin_types_compatible_p(typeof(x), double))                 \
      tmp = (typeof(x))DBL_MAX;                                               \
    else                                                                      \
      abort ();                                                               \
    tmp;                                                                      \
  })


int main(void)
{
    short       num_short;
    int         num_int;
    double      num_double;
    signed char num_char;


    printf("  %ld max short\n",     TYPEOF_MAX(num_short));
    printf("  %ld max int\n",       TYPEOF_MAX(num_int));
    printf("  %f  max double\n",    TYPEOF_MAX(num_double));
    printf("  %ld max char\n",      TYPEOF_MAX(num_char));
    return 0;
}

答案 2 :(得分:2)

此示例使用基于@Pedro Henrique A. Oliveira的答案的C11泛型,

注意,它可以添加更多类型(ssize_t size_t intptr_t ...等)。

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include <stdint.h>

#define TYPEOF_MAX(x) \
    _Generic(x, \
        bool: 1, \
        char: CHAR_MAX, signed char: SCHAR_MAX, unsigned char: UCHAR_MAX, \
        signed short: SHRT_MAX, unsigned short: USHRT_MAX, \
        signed int: INT_MAX, unsigned int: UINT_MAX, \
        signed long: LONG_MAX, unsigned long: ULONG_MAX, \
        signed long long: LLONG_MAX, unsigned long long: ULLONG_MAX, \
        float: FLT_MAX, double: DBL_MAX)


#define TYPEOF_MIN(x) \
    _Generic(x, \
        bool: 0, \
        char: CHAR_MIN, signed char: SCHAR_MIN, unsigned char: 0, \
        signed short: SHRT_MIN, unsigned short: 0, \
        signed int: INT_MIN, unsigned int: 0, \
        signed long: LONG_MIN, unsigned long: 0, \
        signed long long: LLONG_MIN, unsigned long long: 0, \
        float: -FLT_MAX, double: -DBL_MAX)

/* change 100 to 1000 - static asserts work! */
_Static_assert(TYPEOF_MAX((char)4) > 100, "example check");


int main(void)
{
    short       num_short;
    int         num_int;
    double      num_double;
    signed char num_char;


    printf("  %ld max short\n",     TYPEOF_MAX(num_short));
    printf("  %ld max int\n",       TYPEOF_MAX(num_int));
    printf("  %f  max double\n",    TYPEOF_MAX(num_double));
    printf("  %ld max char\n",      TYPEOF_MAX(num_char));
    return 0;
}

答案 3 :(得分:0)

如果您愿意对数字表示做出假设而不是陷入标准(支持您几乎不可能关心的体系结构),那么您可以将~0填入目标变量中输入(对于无符号类型),然后将该值赋给max。对于签名(或可能已签名)的类型,您填写~0并查看a < 0。如果是这样,假设2的补码并从那里开始。您已经确定long long可以保存您关注的任何类型的任何值,因此您可以在粉碎它之前存储a的副本(假设这个技巧只能在{{}}下工作1}})。

我刚刚发布了一个测试示例来验证这一切都通过普通优化(使用gcc)减少到常量:

a