是的,结果如您所愿。
让我们分解一下。
此时r 的值是多少?好吧,下溢是明确定义的,导致r 在运行比较时达到最大值。 std::size_t has no specific known bounds,但与int 相比,我们可以对其范围做出合理的假设:
std::size_t 是 sizeof 运算符结果的无符号整数类型。 [..]std::size_t 可以存储理论上可能的任何类型(包括数组)对象的最大大小。
而且,为了避免妨碍,表达式-1 是应用于文字1 的一元-,并且在任何系统上都具有int 类型:
[C++11: 2.14.2/2]: 整数文字的类型是表 6 中可以表示其值的相应列表中的第一个。 [..]
(我不会引用所有描述如何将一元 - 应用于 int 导致 int 的文本,但确实如此。)
建议在大多数系统上,int 将无法容纳 std::numeric_limits<std::size_t>::max(),这是非常合理的。
现在,这些操作数会发生什么?
[C++11: 5.10/1]: ==(等于)和!=(不等于)运算符与关系运算符具有相同的语义限制、转换和结果类型,但它们的优先级较低且结果为真值. [..]
[C++11: 5.9/2]: 通常的算术转换是在算术或枚举类型的操作数上执行的。 [..]
让我们来看看这些“常见的算术转换”:
[C++11: 5/9]: 许多期望算术或枚举类型的操作数的二元运算符会以类似的方式导致转换和产生结果类型。目的是产生一个通用类型,也就是结果的类型。
这种模式称为常用的算术转换,定义如下:
- 如果任一操作数属于范围枚举类型 (7.2),则不执行任何转换;如果另一个
操作数的类型不同,表达式格式不正确。
- 如果任一操作数的类型为
long double,则另一个应转换为 long double`。
- 否则,如果任一操作数为
double,则另一个应转换为double。
- 否则,如果任一操作数为
float,则另一个应转换为float。
- 否则,应在两个操作数上执行整数提升 (4.5)。59 然后应将以下规则应用于提升的操作数:
- 如果两个操作数的类型相同,则无需进一步转换。
- 否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则
具有较小整数转换等级类型的操作数应转换为
具有更高等级的操作数。
- 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为
无符号整数类型的操作数的类型。
- 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为带符号整数类型的操作数的类型输入。
- 否则,两个操作数都应转换为对应的无符号整数类型
带符号整数类型的操作数的类型。
我已经强调了这里生效的段落,至于为什么:
[C++11: 4.13/1]:每个整数类型都有一个整数转换等级,定义如下
- [..]
-
long long int的rank大于long int的rank,int的rank大于short int的rank,大于short int的rank signed char 的排名。
- 任何无符号整数类型的等级应等于相应有符号整数类型的等级。
- [..]
所有整数类型,即使是固定宽度的,都由标准整数类型组成;因此,从逻辑上讲,std::size_t 必须是 unsigned long long、unsigned long 或 unsigned int。
无论哪种方式,根据通常的算术转换,有符号操作数都被转换为无符号操作数的类型(而且,至关重要的是,不是反过来!) .现在,这种转换意味着什么?
[C++11: 4.7/2]: 如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n 其中 n 是用于表示无符号类型的位数)。 [ 注意: 在二进制补码表示中,这种转换是概念性的,在位模式(如果没有截断)。 ——尾注]
[C++11: 4.7/3]:如果目标类型是有符号的,如果可以在目标类型(和位域宽度)中表示,则值不变;否则,该值是实现定义的。
这意味着std::size_t(-1)等价于std::numeric_limits<std::size_t>::max();至关重要的是,上述子句中的值 n 与用于表示 unsigned 类型的位数相关,而不是源类型。否则,我们将使用std::size_t((unsigned int)-1),这根本不是一回事——它可能比我们想要的值小很多数量级!
确实,既然我们知道转换都是明确定义的,我们可以测试这个值:
std::cout << (std::size_t(-1) == std::numeric_limits<size_t>::max()) << '\n';
// "1"
而且,为了说明我之前的观点,在我的 64 位系统上:
std::cout << std::is_same<unsigned long, std::size_t>::value << '\n';
std::cout << std::is_same<unsigned long, unsigned int>::value << '\n';
std::cout << std::hex << std::showbase
<< std::size_t(-1) << ' '
<< std::size_t(static_cast<unsigned int>(-1)) << '\n';
// "1"
// "0"
// "0xffffffffffffffff 0xffffffff"