未知大小的有符号整数类型的最大正值

Largest positive value of a signed integer type of unknown size

如果我们有一个我们可能不知道其大小的无符号整数类型,例如 size_t,那么我们可以相对简单地获得它可以容纳的最大值,例如:

size_t maximal = -1;

有符号整数类型有类似的技术吗,例如ssize_t?如:

ssize_t smaximal = ???;

注意,可能没有对应的unsigned类型,例如time_t (暂时忽略可能连整数都不是).

[编辑 1] size_t/ssize_t/time_t 的使用仅用于说明目的,我正在寻找没有 XXX_MAX 帮助的通用解决方案.

[编辑 2] 这似乎有效,但我不确定这是否 "just luck":

#include "foo_library_with_no_max_macros_because_they_are_dumb.h"

foo_int_type foo = (((unsigned)-1) >> 1);

foo_int_type 的实际类型是通过一些我不想复制的可怕的预处理器 goop 确定的)

您可以只使用 <limits.h>:

中定义的常量
#include <limits.h>

size_t maximal = SIZE_T_MAX;
ssize_t smaximal = SSIZE_MAX;

AFAIK 签名类型没有简单、完全可移植的方法。 您可以将 *_MAX 宏放在 _Generic 宏中,然后您就不必再担心它们了。

#define Z_max(X) \
    _Generic(X,                                                                \
            char: CHAR_MAX,                                                    \
                                                                               \
            signed char: SCHAR_MAX,                                            \
            short: SHRT_MAX,                                                   \
            int: INT_MAX,                                                      \
            long: LONG_MAX,                                                    \
            long long: LLONG_MAX,                                              \
                                                                               \
            unsigned char: UCHAR_MAX,                                          \
            unsigned short : USHRT_MAX,                                        \
            unsigned int: UINT_MAX,                                            \
            unsigned long: ULONG_MAX,                                          \
            unsigned long long: ULLONG_MAX                                     \
        )                                                                      \

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

int main()
{
    printf("%d\n",  Z_max(1)); //prints 2147483647 on my system
}

我找不到表达式,但找到了使用循环的函数

#define integer int    /* change as required */
integer max()
{
  integer x=0x7f;
  size_t  n=sizeof(integer)-1;
  while(n--) {
    x <<= 8;           /* may create spurious warning for integer=signed char */
    x |= 0xff;
  }
  return x; 
}

或宏

#define MaxSignedInteger(integer)                    \
  (integer)(sizeof(integer)==1? 0x7f :               \
            sizeof(integer)==2? 0x7fff :             \
            sizeof(integer)==4? 0x7fffffff :         \
                                0x7fffffffffffffffll)

如果您不知道类型的大小并且没有库支持来确定最大值,您可以求助于利用二进制表示。

表示有符号整数的常用方法是使用 the Two's complement。二进制补码中有符号类型的最大值是一个零后跟一个 (011111...111)。

现在如何获取那个值呢?我们需要从一个已知值开始,使用按位运算来获得想要的结果。已知值:

  • 0 = 0000...000
  • 1 = 0000...001

没什么用。但是

  • -1 = 1111...111

让我们很接近。现在我们不知道常量 FOO_MIN == 1000...000 我们可以用 -1 来 XOR() ,所以我们可以求助于位移。如果我们将 -1 右移一位并确保将 0 移入,我们将得到所需的值。

在 C 中,负值的右移是实现定义的,因此它可以是算术(在 1 中移位)和逻辑(在 0 中移位)移位,并且它主要是算术的(参见 this answer),因此我们需要在转换之前将值转换为足够大的无符号类型。

这里是:

#include <stdint.h>
#include "foo_library_with_no_max_macros_because_they_are_dumb.h"

foo_int_type foo = ((uint64_t)((foo_int_type)-1)) >> 1;

或者,我们可以使用 sizeof() 生成 FOO_MIN

#include "foo_library_with_no_max_macros_because_they_are_dumb.h"

foo_int_type foo_min = ((foo_int_type)1) << (8 * sizeof(foo_min) - 1);
foo_int_type foo = ((foo_int_type)-1) ^ foo_min;