未知大小的有符号整数类型的最大正值
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;
如果我们有一个我们可能不知道其大小的无符号整数类型,例如 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;