为什么 numeric_limits<uint16_t>::max() 不等于 -1?
Why is numeric_limits<uint16_t>::max() not equal to -1?
#include <iostream>
#include <cstdint>
using namespace std;
static_assert(-1 == numeric_limits<uint64_t>::max()); // ok
static_assert(-1 == numeric_limits<uint32_t>::max()); // ok
static_assert(-1 == numeric_limits<uint16_t>::max()); // error
int main()
{
cout << numeric_limits<uint16_t>::max() << endl;
cout << uint16_t(-1) << endl;
}
输出:
65535
65535
为什么numeric_limits<uint16_t>::max()
不等于-1?
更新:
根据cppref:
Similarly USHRT_MAX may not be of an unsigned type: its type may be
int.
因为 -1
未转换为 uint16_t
。
std::numeric_limits<std::uint16_t>::max()
升级为 int
,-1 != 65535
.
整数转化和促销
uint16_t
值经过 整数提升 而对于(您的特定平台;见下文)uint32_t
和 uint64_t
情况-1
value(本身不是整数文字,而是应用于整数文字 1
的一元减号运算符),经过 integer由于此转换的源值和目标值之间的整数一致,转换 的结果值等于 uint32_t
和 uint64_t
类型的最大值。 =94=]
static_assert(-1 == std::numeric_limits<std::uint64_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint64_t
// | Resulting value: std::numeric_limits<std::uint64_t>::max()
static_assert(-1 == std::numeric_limits<std::uint32_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint32_t
// | Resulting value: std::numeric_limits<std::uint32_t>::max()
static_assert(-1 == std::numeric_limits<std::uint16_t>::max());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | Integer promotion:
// | Destination type: int
// | Resulting value: std::numeric_limits<std::uint16_t>::max()
来自 [expr.eq]/1 and [expr.eq]/6 [强调 我的]:
[expr.eq]/1
The ==
(equal to) and the !=
(not equal to) operators group
left-to-right. The operands shall have arithmetic, enumeration,
pointer, or pointer to member type, or type std::nullptr_t
. The
operators ==
and !=
both yield true
or false
, i.e., a result
of type bool
. In each case below, the operands shall have the same
type after the specified conversions have been applied.
[expr.eq]/6
If both operands are of arithmetic** or enumeration type, the usual arithmetic conversions are performed on both operands; each of
the operators shall yield true
if the specified relationship is
true
and false
if it is false
.
来自 [conv.integral]/1 and [conv.integral]/2:
[conv.integral]/1
A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.
[conv.integral]/2
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n
where n
is the number of bits used to represent the unsigned type). [ Note: In a two's complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note ]
仅此一项就应该为所有三个示例产生相同的行为。但是,uint16_t
案例的不同之处在于 [conv.integral]/5 适用:
[conv.integral]/5
The conversions allowed as integral promotions are excluded from the set of integral conversions.
[conv.rank]/1
Every integer type has an integer conversion rank defined as follows:
[...]
(1.3) The rank of long long int
shall be greater than the rank of long
int
, which shall be greater than the rank of int
, which shall be
greater than the rank of short int
, which shall be greater than the
rank of signed char
.
(1.4) The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.
uint16_t
的整数转换等级(与short int
相同等级或低于short int
)低于int
,即[conv.prom]/1申请uint16_t
[强调我的]:
[conv.prom]/1
A prvalue of an integer type other than bool
, char16_t
, char32_t
, or wchar_t
whose integer conversion rank is less than the rank of int
can be converted to a prvalue of type int
if int
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int
.
平台相关行为
但是,虽然由于最大值[=139]的下限要求,我们能够对上面的uint16_t
进行论证=] 的 unsigned short int
——保证 uint16_t
总是比 int
具有更低的整数转换等级——我们不能对 uint32_t
将 [=120] 的事实进行相反的论证=]永远不会 整数转换等级 低于 int
,因为 ISO C++ 标准没有 最大值 对基本整数类型的要求。
来自 [basic.fundamental]/2 and [basic.fundamental]/3 [摘录,强调 我的]:
[basic.fundamental]/2
There are five standard signed integer types : “signed char
”,
“short int
”, “int
”, “long int
”, and “long long int
”. In this
list, each type provides at least as much storage as those preceding
it in the list. [...] Plain int
s have the natural size suggested
by the architecture of the execution environment; the other signed
integer types are provided to meet special needs.
[basic.fundamental]/3
For each of the standard signed integer types, there exists a
corresponding (but different) standard unsigned integer type:
“unsigned char
”, “unsigned short int
”, “unsigned int
”,
“unsigned long int
”, and “unsigned long long int
”, each of which
occupies the same amount of storage and has the same alignment
requirements as the corresponding signed integer type; [...]
The signed and unsigned integer types shall satisfy the constraints
given in the C standard, section 5.2.4.2.1.
并且,从 C11 Standard draft [摘录,强调 我的]:
5.2.4.2.1 Sizes of integer types <limits.h>
[...] Their implementation-defined values shall be equal or greater
in magnitude (absolute value) to those shown, with the same sign.
[...]
maximum value for an object of type short int
: SHRT_MAX +32767
maximum value for an object of type int
: INT_MAX +32767
[...]
请注意,这些最大值描述了相应基本整数类型应能够存储的最大值的下限,而对这些最大值的上限没有要求。此外,回想一下上面的 [basic.fundamental]/2 引用,每个后续的基本(有符号)整数类型只需要提供 至少 与处理它的那个一样多的存储空间(在名单)。
这意味着,理论上,一个平台可以将 short int
和 int
分别实现为 32 位宽和 64 位宽的整数,这意味着,在这个平台上,uint32_t
将具有与 (unsigned
) short int
相同的整数转换等级,这意味着 低于 转换等级 int
,在这种情况下 [conv.prom]/1
也适用于 uint32_t
示例 在此特定平台上 .
#include <iostream>
#include <cstdint>
using namespace std;
static_assert(-1 == numeric_limits<uint64_t>::max()); // ok
static_assert(-1 == numeric_limits<uint32_t>::max()); // ok
static_assert(-1 == numeric_limits<uint16_t>::max()); // error
int main()
{
cout << numeric_limits<uint16_t>::max() << endl;
cout << uint16_t(-1) << endl;
}
输出:
65535
65535
为什么numeric_limits<uint16_t>::max()
不等于-1?
更新:
根据cppref:
Similarly USHRT_MAX may not be of an unsigned type: its type may be int.
因为 -1
未转换为 uint16_t
。
std::numeric_limits<std::uint16_t>::max()
升级为 int
,-1 != 65535
.
整数转化和促销
uint16_t
值经过 整数提升 而对于(您的特定平台;见下文)uint32_t
和 uint64_t
情况-1
value(本身不是整数文字,而是应用于整数文字 1
的一元减号运算符),经过 integer由于此转换的源值和目标值之间的整数一致,转换 的结果值等于 uint32_t
和 uint64_t
类型的最大值。 =94=]
static_assert(-1 == std::numeric_limits<std::uint64_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint64_t
// | Resulting value: std::numeric_limits<std::uint64_t>::max()
static_assert(-1 == std::numeric_limits<std::uint32_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint32_t
// | Resulting value: std::numeric_limits<std::uint32_t>::max()
static_assert(-1 == std::numeric_limits<std::uint16_t>::max());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | Integer promotion:
// | Destination type: int
// | Resulting value: std::numeric_limits<std::uint16_t>::max()
来自 [expr.eq]/1 and [expr.eq]/6 [强调 我的]:
[expr.eq]/1
The
==
(equal to) and the!=
(not equal to) operators group left-to-right. The operands shall have arithmetic, enumeration, pointer, or pointer to member type, or typestd::nullptr_t
. The operators==
and!=
both yieldtrue
orfalse
, i.e., a result of typebool
. In each case below, the operands shall have the same type after the specified conversions have been applied.[expr.eq]/6
If both operands are of arithmetic** or enumeration type, the usual arithmetic conversions are performed on both operands; each of the operators shall yield
true
if the specified relationship istrue
andfalse
if it isfalse
.
来自 [conv.integral]/1 and [conv.integral]/2:
[conv.integral]/1
A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.
[conv.integral]/2
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo
2n
wheren
is the number of bits used to represent the unsigned type). [ Note: In a two's complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note ]
仅此一项就应该为所有三个示例产生相同的行为。但是,uint16_t
案例的不同之处在于 [conv.integral]/5 适用:
[conv.integral]/5
The conversions allowed as integral promotions are excluded from the set of integral conversions.
[conv.rank]/1
Every integer type has an integer conversion rank defined as follows:
[...]
(1.3) The rank of
long long int
shall be greater than the rank oflong int
, which shall be greater than the rank ofint
, which shall be greater than the rank ofshort int
, which shall be greater than the rank ofsigned char
.(1.4) The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.
uint16_t
的整数转换等级(与short int
相同等级或低于short int
)低于int
,即[conv.prom]/1申请uint16_t
[强调我的]:
[conv.prom]/1
A prvalue of an integer type other than
bool
,char16_t
,char32_t
, orwchar_t
whose integer conversion rank is less than the rank ofint
can be converted to a prvalue of typeint
ifint
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of typeunsigned int
.
平台相关行为
但是,虽然由于最大值[=139]的下限要求,我们能够对上面的uint16_t
进行论证=] 的 unsigned short int
——保证 uint16_t
总是比 int
具有更低的整数转换等级——我们不能对 uint32_t
将 [=120] 的事实进行相反的论证=]永远不会 整数转换等级 低于 int
,因为 ISO C++ 标准没有 最大值 对基本整数类型的要求。
来自 [basic.fundamental]/2 and [basic.fundamental]/3 [摘录,强调 我的]:
[basic.fundamental]/2
There are five standard signed integer types : “
signed char
”, “short int
”, “int
”, “long int
”, and “long long int
”. In this list, each type provides at least as much storage as those preceding it in the list. [...] Plainint
s have the natural size suggested by the architecture of the execution environment; the other signed integer types are provided to meet special needs.[basic.fundamental]/3
For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type: “
unsigned char
”, “unsigned short int
”, “unsigned int
”, “unsigned long int
”, and “unsigned long long int
”, each of which occupies the same amount of storage and has the same alignment requirements as the corresponding signed integer type; [...]The signed and unsigned integer types shall satisfy the constraints given in the C standard, section 5.2.4.2.1.
并且,从 C11 Standard draft [摘录,强调 我的]:
5.2.4.2.1 Sizes of integer types
<limits.h>
[...] Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
[...]
maximum value for an object of type
short int
:SHRT_MAX +32767
maximum value for an object of type
int
:INT_MAX +32767
[...]
请注意,这些最大值描述了相应基本整数类型应能够存储的最大值的下限,而对这些最大值的上限没有要求。此外,回想一下上面的 [basic.fundamental]/2 引用,每个后续的基本(有符号)整数类型只需要提供 至少 与处理它的那个一样多的存储空间(在名单)。
这意味着,理论上,一个平台可以将 short int
和 int
分别实现为 32 位宽和 64 位宽的整数,这意味着,在这个平台上,uint32_t
将具有与 (unsigned
) short int
相同的整数转换等级,这意味着 低于 转换等级 int
,在这种情况下 [conv.prom]/1
也适用于 uint32_t
示例 在此特定平台上 .