整数转换和促销
uint16_t 值经过整数提升,而对于(您的特定平台;见下文)uint32_t 和uint64_t 情况下-1 值 (本身不是整数文字,而是应用于整数文字1 的一元减号运算符),通过整数转换,结果值等于@ 的最大相应值987654336@ 和 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
整数类型的纯右值可以转换为另一种整数类型的纯右值。非作用域枚举类型的纯右值可以转换为整数类型的纯右值。
[conv.integral]/2
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2n,其中n 是用于表示无符号类型的位数)。 [ 注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 — 尾注 ]
仅此一项就应该为您的所有三个示例产生相同的行为。但是,uint16_t 案例的不同之处在于 [conv.integral]/5 适用:
[conv.integral]/5
作为积分促销允许的转换不包括在积分转换集中。
来自[conv.rank]/1
[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申请uint16_t[强调我的]:
[conv.prom]/1
除bool、char16_t、char32_t或wchar_t以外的整数类型的纯右值其整数转换等级小于int的等级可以转换为type int 如果int 可以表示源类型的所有值;否则,可以将源纯右值转换为unsigned int 类型的纯右值。
平台相关行为
然而,虽然由于unsigned short int 的最大值下限要求,我们能够为上面的uint16_t 提出论据——保证uint16_t 的整数转换等级总是低于 int — 我们不能提出相反的论点,因为uint32_t永远不会低于整数转换等级 int,因为 ISO C++ 标准对基本整数类型的最大值没有上限要求。
来自[basic.fundamental]/2 和[basic.fundamental]/3 [摘录,强调我的]:
[basic.fundamental]/2
有五种标准有符号整数类型:“signed char”,
“short int”、“int”、“long int”和“long long int”。在这个
列表,每种类型提供的存储空间至少与前面的相同
它在列表中。 [...] 普通 ints 有建议的自然尺寸
通过执行环境的架构;另一个签名
提供整数类型以满足特殊需求。
[basic.fundamental]/3
对于每个标准的有符号整数类型,都存在一个
对应的(但不同的)标准无符号整数类型:
“unsigned char”、“unsigned short int”、“unsigned int”、
“unsigned long int”和“unsigned long long int”,每个
占用相同的存储量并具有相同的对齐方式
要求为对应的有符号整数类型; [...]
有符号和无符号整数类型应满足约束
在 C 标准第 5.2.4.2.1 节中给出。
并且,来自C11 Standard draft [摘录,强调我的]:
5.2.4.2.1 整数类型的大小<limits.h>
[...] 它们的实现定义的值应等于或大于
幅度(绝对值)与所示的相同,符号相同。
[...]
[...]
请注意,这些最大值描述了最大值的下限,相应的基本整数类型应该能够存储,而对这些最大值的上限。此外,从上面的 [basic.fundamental]/2 引用中回想一下,每个后续的基本(有符号)整数类型只需要提供 至少 与处理它的那个(在列表中)一样多的存储空间。
这意味着,理论上,一个平台可以将 short int 和 int 分别实现为 32 位宽和 64 位宽的整数,这意味着,在这个平台上,uint32_t 将具有与(unsigned) short int,这意味着比int低于的转化排名,在这种情况下,[conv.prom]/1 也适用于这个特定平台上的uint32_t 示例 .