C:查找算术表达式类型的最大值和最小值

tyt*_*yty 6 c types expression max min

我需要找到没有副作用的任意C表达式的最大值和最小值.以下宏可以在我的机器上运行.他们会在所有平台上工作吗?如果没有,他们可以修改工作吗?我的意图是随后使用这些来实现SAFE_MUL(a,b)代替的宏a*b.SAFE_MUL将包括检查乘法溢出.

编辑:按史蒂夫的建议投射类型.

#include <stdio.h>
#include <limits.h>

#define IS_SIGNED(exp) (((exp)*0-1) < 0)

#define TYPE_MAX_UNSIGNED(exp) ((exp)*0-1)

#define TYPE_MAX_SIGNED(exp) ( \
    sizeof (exp) == sizeof (int) \
    ? \
    INT_MAX \
    : \
    ( \
        sizeof (exp) == sizeof (long) \
        ? \
        LONG_MAX \
        : \
        LLONG_MAX \
    ) \
)

#define TYPE_MAX(exp) ((unsigned long long)( \
    IS_SIGNED (exp) \
    ? \
    TYPE_MAX_SIGNED (exp) \
    : \
    TYPE_MAX_UNSIGNED (exp) \
))

#define TYPE_MIN_SIGNED(exp) ( \
    sizeof (exp) == sizeof (int) \
    ? \
    INT_MIN \
    : \
    ( \
        sizeof (exp) == sizeof (long) \
        ? \
        LONG_MIN \
        : \
        LLONG_MIN \
    ) \
)

#define TYPE_MIN(exp) ((long long)( \
    IS_SIGNED (exp) \
    ? \
    TYPE_MIN_SIGNED (exp) \
    : \
    (exp)*0 \
))

int
main (void) {

    printf ("TYPE_MAX (1 + 1) = %lld\n", TYPE_MAX (1 + 1));
    printf ("TYPE_MAX (1 + 1L) = %lld\n", TYPE_MAX (1 + 1L));
    printf ("TYPE_MAX (1 + 1LL) = %lld\n", TYPE_MAX (1 + 1LL));
    printf ("TYPE_MAX (1 + 1U) = %llu\n", TYPE_MAX (1 + 1U));
    printf ("TYPE_MAX (1 + 1UL) = %llu\n", TYPE_MAX (1 + 1UL));
    printf ("TYPE_MAX (1 + 1ULL) = %llu\n", TYPE_MAX (1 + 1ULL));
    printf ("TYPE_MIN (1 + 1) = %lld\n", TYPE_MIN (1 + 1));
    printf ("TYPE_MIN (1 + 1L) = %lld\n", TYPE_MIN (1 + 1L));
    printf ("TYPE_MIN (1 + 1LL) = %lld\n", TYPE_MIN (1 + 1LL));
    printf ("TYPE_MIN (1 + 1U) = %llu\n", TYPE_MIN (1 + 1U));
    printf ("TYPE_MIN (1 + 1UL) = %llu\n", TYPE_MIN (1 + 1UL));
    printf ("TYPE_MIN (1 + 1ULL) = %llu\n", TYPE_MIN (1 + 1ULL));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*sop 3

  • 对于小于 的无符号类型,宏IS_SIGNED并不能说明真相int。在任何正常实现上都是如此,因为is 、 notIS_SIGNED((unsigned char)1)的类型。(unsigned char)1*0intunsigned char

您的最终SAFE宏仍应说明是否发生溢出的真相,因为相同的整数提升适用于所有算术。但它们会告诉您乘法中是否发生溢出,而不一定是当用户将结果转换回操作数之一的原始类型时是否发生溢出。

不过,想一想,您可能已经知道这一点,因为您的宏不会尝试提出建议CHAR_MIN等等。但将来发现这个问题的其他人可能不会意识到这种限制。

  • 没有任何单一类型能够保证能够保存TYPE_MINTYPE_MAX可以求出的所有值。但是你可以让TYPE_MAXalways评估为(并且该值总是适合该类型),并且与andunsigned long long相同。这将允许您使用正确的 printf 格式,而无需了解表达式是否有符号。当前是 a ,而是 an 。TYPE_MINsigned long longTYPE_MAX(1)long longTYPE_MAX(1ULL)unsigned long long

  • 从技术上讲,由于 和的填充位少于,因此允许intlong具有相同的大小但不同的范围。不过,我怀疑是否有任何重要的实施能够做到这一点。longint