#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:
类似地,USHRT_MAX可能不是无符号类型:其类型可能是
答案 0 :(得分:6)
因为-1
未转换为uint16_t
。
std::numeric_limits<std::uint16_t>::max()
被提升为int
和-1 != 65535
。
答案 1 :(得分:5)
uint16_t
值通过整数提升进行,而对于uint32_t
和uint64_t
情况(您的特定平台;请参见下文),-1
value (本身不是整数文字,但是应用于整数文字1
的一元减号运算符)经过整数转换,结果值为等于uint32_t
和uint64_t
类型的最大相应值,这是由于此转换的源值和目标值之间的整数一致。
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和[expr.eq]/6 [强调我的]:
[expr.eq] / 1
==
(等于)和!=
(不等于)运算符组 左到右。操作数应具有算术,枚举, 指针,或指向成员类型的指针,或键入std::nullptr_t
。的 运算符==
和!=
都产生true
或false
,即结果bool
类型的。在以下每种情况下,操作数应具有相同的值 在应用指定的转化后输入。[expr.eq] / 6
如果两个操作数均为算术**或枚举类型,则通常对两个操作数执行算术转换;每个 如果指定的关系是,则运算符应产生
true
true
和false
(如果是false
。
来自[conv.integral]/1和[conv.integral]/2:
[conv.integral] / 1
可以将整数类型的prvalue转换为另一种整数类型的prvalue。可以将无作用域枚举类型的prvalue转换为整数类型的prvalue。
[conv.integral] / 2
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模数
2n
,其中n
是用来表示无符号类型的位数)。 [注:在二进制补码表示中,此转换是概念性的,并且位模式没有任何变化(如果没有截断)。 —尾注]
对于您的所有三个示例,仅此一项便会产生相同的行为。但是,与uint16_t
情况不同的是,[conv.integral]/5适用:
[conv.integral] / 5
允许作为整体促销的转换不包括在整体转换集中。
[conv.rank] / 1
每个整数类型的整数转换等级定义如下:
[...]
(1.3)
long long int
的等级应大于long int
的等级,其应大于int
的等级,其应为 大于short int
的等级,该等级应大于 排名signed char
。(1.4)任何无符号整数类型的等级应等于相应有符号整数类型的等级。
uint16_t
的整数转换等级(相同等级或低于short int
)低于int
,这意味着[conv.prom]/1适用于{{1} } [强调我的]:
[conv.prom] / 1
除
uint16_t
,bool
,char16_t
或char32_t
以外的整数类型的prvalue 其整数转换等级小于{{如果wchar_t
可以代表源类型的所有值,则可以将1}}转换为类型int
的prvalue;否则,可以将源prvalue转换为类型int
的prvalue。
然而,尽管我们能够对int
进行论证,但由于对{{1}的最大值的下限要求 } –保证unsigned int
始终比uint16_t
的整数转换排名低-我们不能为unsigned short int
永远较低上限。
从[basic.fundamental]/2和[basic.fundamental]/3中摘录,强调是我的]:
[basic.fundamental] / 2
有五种标准的带符号整数类型:“
uint16_t
”, “int
”,“uint32_t
”,“int
”和“signed char
”。在这个 列表中,每种类型提供的存储量至少与之前的存储量相同 在列表中。 [...]普通short int
的具有建议的自然尺寸 根据执行环境的架构;另一个签名 提供了整数类型以满足特殊需求。[basic.fundamental] / 3
对于每种标准的带符号整数类型,都有一个 对应的(但不同的)标准无符号整数类型: “
int
”,“long int
”,“long long int
”, “int
”和“unsigned char
”,每个 占用相同的存储空间并具有相同的对齐方式 要求为相应的带符号整数类型; [...]有符号和无符号整数类型应满足约束 C标准第5.2.4.2.1节中给出。
然后,从C11 Standard draft [摘录,重点我的]:
5.2.4.2.1整数类型
的大小unsigned short int
[...]其实现定义的值应等于或更大 大小(绝对值)与所示的相同,并带有相同的符号。
[...]
类型为
unsigned int
的对象的- 类型为
最大值:
unsigned long int
unsigned long long int
的对象的最大值:
<limits.h>
[...]
请注意,这些最大值描述了相应的基本整数类型应能够存储的最大值的下限,而对这些最大值的上限。此外,从上面的[basic.fundamental] / 2引用中回想起,每个随后的基本(带符号)整数类型仅需要提供至少 个存储空间(与列表中进行存储的存储空间一样大)。
这意味着从理论上讲,平台可以将short int
和SHRT_MAX +32767
分别实现为32位宽和64位宽的整数,这意味着在该平台上,int
将具有与({INT_MAX +32767
)short int
相同的整数转换等级,这意味着转换等级比int
低 低,在这种情况下,将使用uint32_t
同样在该特定平台上的unsigned
示例 。