整数转换和提升
uint16_t
值经过整数提升,而对于(您特定的平台;请参见下文)uint32_t
和uint64_t
情况,-1
值(不是一个整数字面量,而是应用于整数字面量1
的一元减号运算符)经过整数转换,其结果值等于uint32_t
和uint64_t
类型的最大相应值,由于此转换的源值和目标值之间的整数同余关系。
static_assert(-1 == std::numeric_limits<std::uint64_t>::max());
static_assert(-1 == std::numeric_limits<std::uint32_t>::max());
static_assert(-1 == 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
。
从[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
[conv.rank]/1
每个整数类型都有一个整数转换等级,定义如下:
[...]
(1.3) long long int
的等级应大于 long int
的等级,int
的等级应大于 short 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
的整数类型的 prvalue,如果其整数转换等级低于 int
的等级,则可以将其转换为类型为 int
的 prvalue,如果 int
可以表示源类型的所有值;否则,源 prvalue 可以被转换为类型为 unsigned int
的 prvalue。
平台相关行为
然而,虽然我们能够因为无符号短整型的最大值下限要求来证明uint16_t
的优先级总是低于int
的整数转换等级,但我们不能为uint32_t
提出相反的论点,因为ISO C++标准对基本整数类型的最大值没有上限要求。
从[basic.fundamental]/2和[basic.fundamental]/3中提取(强调属于我):
[basic.fundamental]/2
有五种标准的带符号整数类型:“signed char
”、“short int
”、“int
”、“long int
”和“long long int
”。在此列表中,每个类型提供的存储空间至少与它前面的类型相同。[...] 普通的int
具有由执行环境的体系结构建议的自然大小;其他带符号整数类型是为了满足特殊需要而提供的。
[basic.fundamental]/3
对于每个标准带符号整数类型,都存在一个对应的(但不同的)标准无符号整数类型:“unsigned char
”、“unsigned short int
”、“unsigned int
”、“unsigned long int
”和“unsigned long long int
”,每个类型占用与相应的带符号整数类型相同的存储空间并具有相同的对齐要求;[...]
带符号和无符号整数类型必须满足C标准第5.2.4.2.1节中给出的约束条件。
而且,从C11标准草案中提取(强调属于我):
5.2.4.2.1 整数类型的大小
<limits.h>
[...] 它们的实现定义值应该与所示的相等或更大(绝对值),符号相同。
[...]
- 类型为
short int
的对象的最大值:
SHRT_MAX +32767
- 类型为
int
的对象的最大值:
INT_MAX +32767
[...]
请注意,这些最大值描述了各自基本整数类型应该能够存储的最大值的下限,而对于这些最大值的上限没有要求。此外,请回想一下上面的[basic.fundamental]/2引用,每个后续基本(有符号)整数类型只需要提供至少与前面的类型相同的存储空间(在列表中)。
这意味着,理论上,平台可以将
short int
和
int
分别实现为32位宽度和64位宽度的整数,这意味着在此平台上,
uint32_t
将具有与(
unsigned
)
short int
相同的整数转换级别,这将意味着比
int
更低的转换级别,如果是这种情况,则
[conv.prom]/1
也适用于
uint32_t
示例
在此特定平台上。
int
像20世纪80年代一样是16位吗? - Asteroids With Wings